Swift 5+Kingfisher:如何避免Collection View加载图片重复错位?
Kingfisher CollectionView 图片加载错位问题解决思路
问题根源
你手动实现的磁盘缓存检索异步逻辑存在缺陷:ImageCache.default.retrieveImageInDiskCache是异步操作,当CollectionView快速滚动时,回调触发时单元格已经被复用给其他IndexPath,此时将缓存图片设置到复用后的单元格上,就会导致图片错位。而Kingfisher的kf.setImage方法内部已经封装了完整的缓存读取、复用任务管理逻辑,不需要手动干预缓存查询。
解决方案
1. 移除手动缓存检索逻辑,直接使用Kingfisher原生加载方法
删除自定义的磁盘缓存查询代码,让kf.setImage自动处理内存/磁盘缓存的读取、下载任务管理,以及单元格复用的正确性保障。
修改后的cellForItemAt代码:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SimpleThumbnailView", for: indexPath) as! ThumbnailsCollectionViewCell cell.prepareForReuse() if indexPath.row < thumbnails.count { let item = thumbnails[indexPath.row] let urlString = item.thumbnail ?? "" if let url = URL(string: urlString) { let resource = ImageResource(downloadURL: url, cacheKey: urlString) cell.thumbnailImage.kf.setImage( with: resource, placeholder: UIImage(named: "DefaultImage"), options: [ .transition(.fade(0.2)) // 可选:添加淡入过渡提升体验 ] ) } else { cell.thumbnailImage.image = UIImage(named: "DefaultImage") } cell.titleLabel.text = item.title cell.authorLabel.text = StringBuilder.authorLikes(author: item.writer, likes: item.likeCount) cell.articleId = item.articleId cell.authorId = item.writer if cell.articleId != -1 { cell.removePlaceHolder() } } else { thumbnailCollectionView.reloadData() } return cell }
2. 完善prepareForReuse方法
确保单元格复用时彻底重置所有内容,避免残留数据影响:
override func prepareForReuse() { super.prepareForReuse() // 取消当前图片加载任务 thumbnailImage.kf.cancelDownloadTask() // 重置图片为占位图 thumbnailImage.image = UIImage(named: "DefaultImage") // 重置文本内容及标识 titleLabel.text = nil authorLabel.text = nil articleId = -1 authorId = nil }
关键说明
- Kingfisher的
kf.setImage会自动优先读取内存缓存,内存缓存未命中时读取磁盘缓存,都没有才发起网络请求,完全覆盖你手动实现的缓存逻辑。 - 该方法内部会绑定单元格的生命周期,当单元格被复用时,自动取消旧的加载任务,避免异步回调导致的错位问题。
- 无需在
cellForItemAt中手动调用cancelDownloadTask,prepareForReuse中的调用已经足够。
内容的提问来源于stack exchange,提问作者Runnan
相关产品推荐
相关产品推荐

