聊聊iOS中UITableView复用的那些事

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

今天跟大家聊聊在开发中我们所遇到的tableView复用的那些事,相信大家在使用tableView或者collectionView时,都会遇到cell复用导致UI错乱。在这篇文章中,我总结了一下几点。

UITableView中的复用机制,想必大家应该都很清楚了。这里就先简单提一下:

tableview新建的时候,会新建一个复用池(reuse pool)。这个复用池可能是一个数组,或者是一个链表,保存着当前的cell。pool中的对象的复用标识符就是reuseIdentifier,标识着不同的种类的cell。调用dequeueReusableCellWithIdentifier:方法获取cell。从pool中取出来的cell都是tableview展示的原型。无论之前有什么状态,全部都要设置一遍。

这里我们就不对tableview的复用机制过多的探讨,只讲讲平时开发容易忽略的复用的问题。

我列举了以下几种情况:

  • 在cell中条件判断没有覆盖全场景
  • 在cell中使用了延迟或者异步处理
  • 在cell中UIImageView混用了网络图片和本地图片

在更新cell的条件判断没有覆盖全场景,只处理了某种条件下UI,其他的没有处理

if xx {
    aLabel.isHidden = true
    avatarView.isHidden = false
} else if xx {
    aLabel.isHidden = false
    avatarView.isHidden = true
} else {
    aLabel.isHidden = true
}
复制代码

在某些时候,cell可能会用来兼容很多情况,或者某一个的cell有很多状态,有时候因为疏忽导致没有处理全部的情况,常常出现了不该显示的UI元素显示出来了。

因为tableview中的cell在使用标识符之后就会被复用,那么我们就需要针对复用的cell去做格式化处理。比如每次刷新时,重制状态。这样就可以保证它的状态是正常的,而不是上一次遗留的。

在cell中的使用了延迟或者异步处理

if xx {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        avatarView.image = UIImage.init("123")
    }
} else {
    xxxx
}
复制代码

有些时候,在cell中使用了延迟来处理某些逻辑。比如使用GCD或者异步回调来更新UI上的显示,可能会有tableView刷新时复用问题,所以在使用延迟时,需要格外注意延迟后的逻辑判断,在重新刷新时取消延迟处理或异步操作。

在cell中使用UIImageView加载网络图片和本地图片

if xx {
    avatarView.image = UIImage.init("123")
} else {
    avatarView.kf.setImage(with: url)
}
复制代码

在cell中我们会经常使用到网络图片加载库来加载网络图片。在某些场景下,我们会将某个UIImageView既用来加载网络图片,也用来加载本地图片。如果有使用场景下我们将一个控件用来处理本地、网络两种情况,那么需要注意,再给加载本地图片时取消网络图片的下载 sd_cancelCurrentImageLoad,或者不要使用同一个控件来加载网络、本地图片;

原因:加载本地图片是同步进行的,而加载网络图片是异步的,有可能我们在刷新时,加载本地图片。但是上次加载的网络图片还未加载完,这时,如果等上次的网络图片加载完成后,那么这个图片就会造成复用了。

总结下来,容易被忽视的其实还是在cell中有异步的操作。

猜你喜欢

转载自juejin.im/post/7101679005534781454