嵌入在容器中的 UITableView 不刷新
Posted
技术标签:
【中文标题】嵌入在容器中的 UITableView 不刷新【英文标题】:UITableView embedded in container not refreshing 【发布时间】:2016-02-23 23:04:01 【问题描述】:简而言之,我想确定用户的位置,从源中获取一些 JSON 数据(这需要首先知道位置),然后根据返回的数据创建一个表。
我在 Xcode 7 中有一个使用 Swift 的自定义 UITableView 和一个原型单元。当这个表视图是初始视图时,它加载得很好。
现在,我正在尝试 1) 将其嵌入到另一个 UIView 的容器中,并且 2) 在其数据更改时更新它。两者都不起作用......容器中的表格永远不会出现。我在这上面花了将近一个星期的时间,现在有点疯狂(这是我的第一个 ios 应用)。
我注意到的一些事情:
-
reloadData、setNeedsDisplay 和 setNeedsLayout 似乎没有任何作用。
cellForRowAtIndexPath 未被调用,但 numberOfRowsInSection 被调用。
我尝试从父 UIView 和 TableViewController 调用项目符号 1 中列出的所有函数。
下面是代码当前的样子: 视图控制器:
import UIKit
import MapKit
import CoreLocation
var currentLatLong: String = ""
class ViewController: UIViewController, CLLocationManagerDelegate
// global var for location
let locationManager = CLLocationManager()
var currentLocation = CLLocation()
var lastLatLong: String = ""
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// get permission and user's location
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled()
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.startUpdatingLocation()
else
print("Location services are not enabled")
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
if let location = locations.last
currentLocation = locations.last!
currentLatLong = "\(currentLocation.coordinate.latitude)%2C\(currentLocation.coordinate.longitude)"
if lastLatLong != currentLatLong
lastLatLong = currentLatLong
NSNotificationCenter.defaultCenter().postNotificationName("updateOverview", object: nil)
self.view.setNeedsDisplay()
self.view.setNeedsLayout()
print("Found user's location: \(location)")
//print("Found user's location: \(location)")
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
print("Failed to find user's location: \(error.localizedDescription)")
UITableViewController:
import UIKit
import MapKit
import CoreLocation
class OverviewTableViewController: UITableViewController
var LocRepositories = [LocationJSON]()
var TimesRepositories = [TimesJSON]()
var retrieved = [dataModelDefn]()
override func viewDidLoad()
super.viewDidLoad()
NSNotificationCenter.defaultCenter().removeObserver(self, name: "updateOverview", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "checkRes", name: "updateOverview", object: nil)
// fetch location data
let backgroundQueue:dispatch_queue_t = dispatch_queue_create("com.example.workQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(backgroundQueue,
self.getLocations()
dispatch_async(dispatch_get_main_queue(), self.tableView.reloadData())
)
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
return 1
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return retrieved.count
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
// initialize data & cell
var cell = tableView.dequeueReusableCellWithIdentifier("EDOverviewCell", forIndexPath: indexPath) as! OverviewTableCell
var rowData = retrieved[indexPath.row]
/* update cell */
// border for cell
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
self.tableView.separatorColor = UIColor(red:(0/255.0), green:(128/255.0), blue:(128/255.0), alpha:1)
// alternating row colors
if indexPath.row % 2 == 0
cell.backgroundColor = UIColor(red:(249/255.0), green:(238/255.0), blue:(188/255.0), alpha:0.5)
else
cell.backgroundColor = UIColor(red:(252/255.0), green:(244/255.0), blue:(220/255.0), alpha:0.5)
return cell
func checkRes()
// fetch new data because location available
getLocations()
//self.tableView.reloadData()
//dispatch_async(dispatch_get_main_queue(), self.tableView.reloadData() )
func getLocations()
// fetch demographic/location info
// abort call if no location
if currentLatLong == ""
return
/* get JSON data */
以下是我试图模仿解决方案的一些相关问题: Loading data after one second in uitableview. Any alternate way to eliminate this delay
How to stop UITableView from loading until data has been fetched?
UITableView doesn't populate when waiting for CLLocationManagerDelegate 's didUpdateToLocation method on iPhone SDK
这篇文章很长,但如果我遗漏了任何必要的细节,请告诉我。感谢您的帮助。
【问题讨论】:
在 getLocations() 中 currentLatLong 是否曾经是一个非空字符串?当您在新视图中嵌入 uitableview 时,通常不会保留整个 uitableviewcontroller。您只需将 tableview 设置为第一个视图控制器的子视图,并根据需要实现 UITableViewDataSource 和 UITableViewDelegate。 试试Xcode View Debugger看看tableview在哪里。也许有一个约束迫使它离开屏幕。另外,从 numberOfRowsInSection 返回的值是否不是 0? @Clever - 我什至不知道它的存在。一旦我让表中的数据出现但它更小并且完全偏离目标,它确实有助于解决一个问题。这是一个超级有用的实用程序。 【参考方案1】:您目前有以下代码:
let backgroundQueue:dispatch_queue_t = dispatch_queue_create("com.example.workQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(backgroundQueue,
self.getLocations()
dispatch_async(dispatch_get_main_queue(), self.tableView.reloadData())
)
这将在后台线程中运行getLocations
,然后在主线程上刷新表tableView。都好。然而,getLocations
本身做了一个 JSON 调用(目前只是一个注释),这无疑也是在另一个后台线程上运行的。因此,getLocations
将几乎立即返回,远在 JSON 完成之前。
您应该将完成处理程序传递给getLocations
,当 JSON 完成时(在其完成处理程序中),调用您自己的完成处理程序。大致如下:
let backgroundQueue:dispatch_queue_t = dispatch_queue_create("com.example.workQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(backgroundQueue,
self.getLocations(completion:
dispatch_async(dispatch_get_main_queue(),
self.tableView.reloadData()
)
)
)
(我这里的大括号可能不匹配)。那么getLocations
定义为:
func getLocations(completion completion: (() -> Void))
// fetch demographic/location info
// abort call if no location
if currentLatLong == ""
return
getTheJsonAndInItsCompletion(... success:
completion()
)
实际的 JSON 实现取决于您使用的库。
【讨论】:
感谢@Michael 的解决方案以及回调地狱的简短介绍。自从您发布答案以来,我一直在阅读它。我没有为 JSON 使用 3rd-party 库,只是 Swift。但是该 JSON 调用中有另一个 JSON 调用,以及一个 ETA(MapKit 框架)调用。不知道如何正常处理,但一场噩梦。以上是关于嵌入在容器中的 UITableView 不刷新的主要内容,如果未能解决你的问题,请参考以下文章
Swift:使用 prepareForSegue 将 UIView 容器的高度设置为嵌入式 UITableView 的高度
将 UITableView 作为容器视图嵌入到 UIViewController 中