我们在修改TableView的数据后,经常使用下面这句
[self.tableView reloadData];
来更新UI
但,其实,这里埋了一个坑,这句代码执行后, 按理说,应该执行numberOfRowsInSection
和CellForRow
方法,测试结果却是代码立即返回,即,整个过程是异步的.
多说一句,毕竟我们是看不到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
,但是cellForRowAt
和heightForRow
是异步调用,回到当前RunLoop,布局cell时才会被调用.
reloadData
这样的特性就导致了没有及时调用相对应的代理方法,如果在reloadData
之后,我们想要执行某些操作,就会导致出现不可预见的结果.
解决方法
想要调用reloadData
之后立即调用所有代理方法,我们可以添加layoutIfNeeded
让TableView强制布局
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
控制台打出的Log如下:
Reload Begin
numberOfRowsInSection
cellForRowAt
heightForRow
…
Reload End
总结
对于CollectionView有同样的问题.
针对这些细节,只有在平时的工作学习中多总结,在遇到问题时,才能更加从ß容. 还有,一定善用StackOverFlow等社区力量,在解决问题时能如虎添翼.