iOS开发攻城狮的集散地iOS点点滴滴bugs

UITableView ReloadData那些坑

2018-01-30  本文已影响1158人  死神一护

我们在修改TableView的数据后,经常使用下面这句[self.tableView reloadData]; 来更新UI

但,其实,这里埋了一个坑,这句代码执行后, 按理说,应该执行numberOfRowsInSectionCellForRow方法,测试结果却是代码立即返回,即,整个过程是异步的.

多说一句,毕竟我们是看不到reloadData 执行的源代码

发现问题

测试代码如下:

 @IBAction func refresh(_ sender: Any) {
        array.removeLast()
        print("Reload Begin")
        self.tableView.reloadData()
        print("Reload End")
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("numberOfRowsInSection")
        return array.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("cellForRowAt")
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
        cell?.textLabel?.text = array[indexPath.row]
        return cell!
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        print("heightForRow")
        return 44;
    }

控制台打出的Log如下:

Reload Begin
numberOfRowsInSection
Reload End
cellForRowAt
heightForRow
…

如上所示,调用reloadData 之后,立即调用numberOfRowsInSection,但是cellForRowAtheightForRow 是异步调用,回到当前RunLoop,布局cell时才会被调用.
reloadData 这样的特性就导致了没有及时调用相对应的代理方法,如果在reloadData之后,我们想要执行某些操作,就会导致出现不可预见的结果.

解决方法

想要调用reloadData 之后立即调用所有代理方法,我们可以添加layoutIfNeeded 让TableView强制布局

self.tableView.reloadData()
self.tableView.layoutIfNeeded()

控制台打出的Log如下:

Reload Begin
numberOfRowsInSection
cellForRowAt
heightForRow
…
Reload End

总结

对于CollectionView有同样的问题.
针对这些细节,只有在平时的工作学习中多总结,在遇到问题时,才能更加从ß容. 还有,一定善用StackOverFlow等社区力量,在解决问题时能如虎添翼.

上一篇下一篇

猜你喜欢

热点阅读