iOS-列表reload异步刷新

1,741 阅读2分钟

「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

问题

可能大部分程序员再开发中对于tableView的reloadData方法是异步执行的不太了解, 但是他确实是异步执行的. 同其他的异步函数一样, 执行完reloadData之后就会 tableView布局, cell的显示以及高度计算 和代理 等一些其他的代码, 因为是异步的, 所以就不会阻塞主线程.

所以reloadData并不会等tableView的代理以及其他的函数执行完毕之后才会返回, 而是立即返回的.

因此我们并无法准确的知道reloadData完成的时机,从而无法及时的处理下一步的操作

尤其是再tableView有很多的数据以及布局比较复杂的情况下, 在reloadData没有执行完毕, 然后就去调用之后的代码的话很可能就出现一些意向不到的问题

 self.tableView?.reloadData()
self.tableView?.scrollToRow(at: IndexPath.init(row: self.selectedIndex, section: 0), at: .none, animated: true)

好比上面这段代码, 就是一个错误的案例, 如果reloadData还没有执行完毕, 那么就要求滚动到指定的行数, 那么必然会出现错误的, 当然还有很多其他的场景存在

解决

那么如果解决上诉的问题呢?

如果可以获取到reloadData的时机,那么就不会出现上述的问题, 可以精准的执行后续的操作, 而不会导致出现问题

1.layoutIfNeeded

使用 layoutIfNeeded 来进行强制重绘,就可以获取到reloadData完成后的时机, 但是有一个问题就是, 使用 layoutIfNeeded 会导致主线程阻塞, 用户的感觉就是卡顿, 这也是一个不好地方所在

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

2.DispatchQueue.main.async

使用 DispatchQueue.main.async 的方式,简单来说就等等主线程空间的时候 再进行操作, 相对来说还是推荐这种方式;

self.tableView?.reloadData()
DispatchQueue.main.async {
    self.tableView?.scrollToRow(at: IndexPath.init(row: self.selectedIndex, section: 0), at: .none, animated: true)
}

结语

一般情况下 我们再写tableView的时候还是不太会遇到这情况, 除非cell上的布局特别的复杂, 其实也可以通过别 的方式来避免这种情况的方式, 好比通过内存换速度的方式等, 如果文章对你有帮助的话, 给个赞吧!