Swift - 异步加载表格数据,内容不能及时显示的问题解决
(本文代码已升级至Swift3)
(2)使用 URLSession 获取远程数据后,调用 tableView的reloadData() 方法重新加载数据。
(3)但会发现数据加载完毕后表格还是空白的,拖动一点点表格数据就显示出来了。
2,解决办法
reloadData() 方法需要在主线程中调用,这样表格数据就能及时更新。(代码高亮出为修改的地方)
1,问题描述
我们使用 tableView 的时候,又是表格内容是异步加载的。比如从网络获取数据显示、或是开启个线程队列定时刷新加载表格数据。
(1)比如我们要加载的数据如下:
[
{
"name": "hangge",
"age": 100,
},
{
"name": "big boss",
"age": 1,
},
{
"name": "batman",
"age": 12,
}
]
(2)使用 URLSession 获取远程数据后,调用 tableView的reloadData() 方法重新加载数据。
import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var ctrlnames:[AnyObject] = [] var tableView:UITableView? override func viewDidLoad() { super.viewDidLoad() //创建表视图 self.tableView = UITableView(frame: self.view.frame, style:.plain) self.tableView!.delegate = self self.tableView!.dataSource = self //创建一个重用的单元格 self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell") self.view.addSubview(self.tableView!) //创建URL对象 let urlString = "http://www.hangge.com/getData.php" let url = URL(string:urlString)! //创建请求对象 let request = URLRequest(url: url) let session = URLSession.shared let dataTask = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in if error != nil{ print(error?.localizedDescription) }else{ self.ctrlnames = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [AnyObject] self.tableView?.reloadData() } }) //使用resume方法启动任务 dataTask.resume() } //在本例中,只有一个分区 func numberOfSections(in tableView: UITableView) -> Int { return 1; } //返回表格行数(也就是返回控件数) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.ctrlnames.count } //创建各单元显示内容(创建参数indexPath指定的单元) func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //为了提供表格显示性能,已创建完成的单元需重复使用 let identify:String = "SwiftCell" //同一形式的单元格重复使用,在声明时已注册 let cell = tableView.dequeueReusableCell(withIdentifier: identify, for: indexPath) as UITableViewCell cell.accessoryType = .disclosureIndicator let item = self.ctrlnames[indexPath.row] cell.textLabel?.text = item.object(forKey: "name") as? String return cell } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
(3)但会发现数据加载完毕后表格还是空白的,拖动一点点表格数据就显示出来了。
2,解决办法
reloadData() 方法需要在主线程中调用,这样表格数据就能及时更新。(代码高亮出为修改的地方)
import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var ctrlnames:[AnyObject] = [] var tableView:UITableView? override func viewDidLoad() { super.viewDidLoad() //创建表视图 self.tableView = UITableView(frame: self.view.frame, style:.plain) self.tableView!.delegate = self self.tableView!.dataSource = self //创建一个重用的单元格 self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell") self.view.addSubview(self.tableView!) //创建NSURL对象 let urlString = "http://www.hangge.com/getData.php" let url = URL(string:urlString)! //创建请求对象 let request = URLRequest(url: url) let session = URLSession.shared let dataTask = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in if error != nil{ print(error?.localizedDescription) }else{ self.ctrlnames = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [AnyObject] DispatchQueue.main.async{ self.tableView?.reloadData() } } }) //使用resume方法启动任务 dataTask.resume() } //在本例中,只有一个分区 func numberOfSections(in tableView: UITableView) -> Int { return 1; } //返回表格行数(也就是返回控件数) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.ctrlnames.count } //创建各单元显示内容(创建参数indexPath指定的单元) func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //为了提供表格显示性能,已创建完成的单元需重复使用 let identify:String = "SwiftCell" //同一形式的单元格重复使用,在声明时已注册 let cell = tableView.dequeueReusableCell(withIdentifier: identify, for: indexPath) as UITableViewCell cell.accessoryType = .disclosureIndicator let item = self.ctrlnames[indexPath.row] cell.textLabel?.text = item.object(forKey: "name") as? String return cell } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
航哥!!很激动,纠结了我一天的问题终于在看到你这个帖子后,解决了,很棒,很好,很好,很好。会经常关顾的!!!!
站长,如果要跳转怎么写
dispatch_async(dispatch_get_main_queue(), {
self.tableView?.reloadData()
return
})
航哥:有return和没return有什么区别呢?
很喜欢这个网站,swift 很详细,学习当中,很赞
不放在主线程,运行中会有错误日志的吧
航哥,如果这个cell里还有一个imageView,json中还有远程图片url,如果这样在cellForRowAtIndexPath方法中,赋值的话,会很卡,这个该怎么优化呢