记录一次Kingfisher使用过程中问题
起因
项目在测试阶段发现一个问题,首页列表数据中可配置背景图的cell发生背景错乱。但是明明已经做了防止复用导致的错乱,如下代码
if let url = URL(string: model.imageUrl) {
ownerImageView.kf.setImage(with: .network(url))
} else {
ownerImageView.image = nil
}
if let backgroundURL = URL(string: model.backgroundImageUrl) {
backgroundImageView.kf.setImage(with: .network(backgroundURL), placeholder: UIImage.home_imageNamed("exprience_cloumn_bg"))} else {
backgroundImageView.image = UIImage.home_imageNamed("exprience_cloumn_bg")
}
代码乍一看好像没啥问题?
刨根
其实,当cell发生错乱的时候,瞬间涌上心头想法就是复用出了问题。但是上边的代码我们已经做了复用了啊。但是我们忽略了一个情况就是异步问题。
利用kf设置图片,本质上是去下载图片或者去缓存里找图片,那么这都是一个异步的过程。如果我们恰好又触发了复用机制,cell从复用池子里取到的cell,很可能是正在下载过程中,那么假设你当前是一个使用默认背景的cell,但是复用取到的是一个正在下载背景的cell。这个时候问题就出现,由于外部设置image比异步快,所以异步回来的图片则覆盖了外边设置的图片。这就是我们出现的本质原因。
接下来我们通过源码看一下:
首先我们进入到内部的setImage方法
当我们设置一个nil的source的话,会触发guard语句,将placeholder直接赋值与imageView的image,并且将当前的taskIdentifier置为nil,这个taskIdentifier作用很大,我们往后看
中间一些option操作不是我们本次重点,我们就看这个。那么第一个红框很重要,在这里会拿当前的任务identifier和ImageView的Identifer比较,不同的话不会赋值,抛出错误。
当然我们也通过log的方式验证了这一点,如下:
至此,从代码层面、验证,都可以证明这个一个异步导致的复用问题。
解决
解决方式也很简单,我们不用自己判断URL空否,因为Kingfisher里边会判断,并且处理,我们都交由其处理即可
let url = URL(string: model.imageUrl)
ownerImageView.kf.setImage(with: url)
backgroundImageView.kf.cancelDownloadTask()
let backgroundImageUrl = URL(string: model.backgroundImageUrl)
backgroundImageView.kf.setImage(with: backgroundImageUrl, placeholder: UIImage.home_imageNamed("exprience_cloumn_bg"))
总结
往往我们只关心同步的复用问题,却忽略了异步复用问题,所以需要特别重要异步导致的复用问题~
往往寻找问题的真正解决方案就藏在代码里,所以我们要多读源码,熟悉三方库源码~