如何借助Kingfisher快速加载UICollectionView可见单元格图片并预取后续图片?
问题分析与优化方案
当前预取实现的问题
你写的prefetchItemsAt存在致命缺陷:当遍历索引路径时,只要遇到一个image为空的项就直接return,导致后续所有有效URL的预取都被终止。这会大幅降低预取的覆盖率,是加载慢的原因之一。
优化步骤与代码修正
1. 修复预取逻辑
用compactMap过滤无效URL,确保即使部分URL为空,其他有效URL仍能正常预取:
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { let carLogoUrlArray = indexPaths.compactMap { carModels[$0.row].image } guard !carLogoUrlArray.isEmpty else { return } let prefetcher = ImagePrefetcher(urls: carLogoUrlArray, options: [ .processor(CarModelViewController.p), .downloadPriority(0.75) ]) prefetcher.start() }
2. 提前启动预取(关键优化)
不要等UICollectionView触发预取,在API返回数据、重载列表后,立刻预取可见区域+即将出现的图片,实现类似Netflix的即时加载:
// 假设API回调获取到数据后执行 func didFetchCarModels(_ models: [CarModel]) { carModels = models collectionView.reloadData() // 1. 预取当前可见的图片(最高优先级) let visibleIndexPaths = collectionView.indexPathsForVisibleItems let visibleUrls = visibleIndexPaths.compactMap { carModels[$0.row].image } let visiblePrefetcher = ImagePrefetcher(urls: visibleUrls, options: [ .processor(CarModelViewController.p), .downloadPriority(1.0) ]) visiblePrefetcher.start() // 2. 预取接下来的20个图片(次高优先级) let nextCount = min(20, carModels.count) let nextIndexPaths = (0..<nextCount).map { IndexPath(row: $0, section: 0) } let nextUrls = nextIndexPaths.compactMap { carModels[$0.row].image } let nextPrefetcher = ImagePrefetcher(urls: nextUrls, options: [ .processor(CarModelViewController.p), .downloadPriority(0.8) ]) nextPrefetcher.start() }
3. 优化Cell复用逻辑
在Cell的prepareForReuse中取消未完成的下载任务,避免旧请求干扰新内容,同时清除旧图片:
class CarModelCollectionViewCell: UICollectionViewCell { @IBOutlet weak var ivCar: UIImageView! override func prepareForReuse() { super.prepareForReuse() ivCar.kf.cancelDownloadTask() ivCar.image = nil // 或设置统一的占位图 } }
4. 全局配置Kingfisher适配小Logo场景
在App启动时优化缓存和下载器参数,提升加载效率:
import Kingfisher func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 缓存配置:小Logo体积小,适当调大缓存上限 let imageCache = ImageCache.default imageCache.diskStorage.config.sizeLimit = 100 * 1024 * 1024 // 100MB磁盘缓存 imageCache.memoryStorage.config.totalCostLimit = 20 * 1024 * 1024 // 20MB内存缓存 // 下载器配置:增加并发数、缩短超时 let imageDownloader = ImageDownloader.default imageDownloader.maxConcurrentDownloads = 10 imageDownloader.downloadTimeout = 8 return true }
5. 确保CollectionView预取功能开启
默认情况下预取是开启的,但可以手动确认:
collectionView.isPrefetchingEnabled = true // 可选:设置预取偏移量,提前预取更多内容 collectionView.prefetchingOffset = 5
其他可选优化
- 给图片URL添加尺寸参数:如果后端支持,直接请求100x100的缩略图,避免客户端二次处理,进一步减少下载体积。
- 占位图优化:设置和Logo风格统一的占位图,提升视觉体验,避免空白等待。
内容的提问来源于stack exchange,提问作者Mel
相关产品推荐
相关产品推荐

