返回 导航

Swift

hangge.com

Swift - 异步加载表格数据,内容不能及时显示的问题解决

作者:hangge | 2016-02-22 09:38
(本文代码已升级至Swift3) 

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()
    }
}
评论

全部评论(6)

回到顶部