图片缓存:如何控制磁盘缓存数量及持久化(Nuke/Kingfisher)
针对你遇到的图片缓存持久化和数量限制问题,我来给你梳理下可行的方案:
用Nuke实现持久化缓存并限制数量
你之前用Nuke时出现离开视图后缓存失效的情况,大概率是没有正确配置磁盘缓存的持久化策略。Nuke默认的磁盘缓存具备持久化能力,但需要手动配置数量限制来满足你“最多20张”的需求:
首先在App启动阶段(比如AppDelegate的didFinishLaunching方法里)自定义缓存配置:
do { // 创建磁盘缓存实例,设置最大缓存数量为20 let diskCache = try DiskCache( name: "com.yourapp.custom.image.cache", sizeLimit: 0, // 不限制缓存总大小,只限制数量 countLimit: 20 ) // 配置全局图片管道 let pipelineConfig = ImagePipeline.Configuration() pipelineConfig.dataCache = diskCache // 可选:同时配置内存缓存的数量限制 pipelineConfig.imageCache = ImageCache(countLimit: 20) ImagePipeline.shared = ImagePipeline(configuration: pipelineConfig) } catch { print("初始化磁盘缓存失败:\(error)") }
之后加载图片时,直接使用全局管道即可,缓存会自动持久化到磁盘,且数量超过20时自动清理最旧的缓存:
ImagePipeline.shared.loadImage(with: url, into: imageView)
优化你的Kingfisher实现(补充数量限制)
你已经用Kingfisher实现了基本的磁盘缓存逻辑,但还没设置数量限制。要达到最多20张的要求,只需要在全局配置里添加限制即可:
同样在App启动时配置:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let defaultCache = ImageCache.default // 设置磁盘缓存最大数量为20 defaultCache.diskStorage.config.countLimit = 20 // 可选:设置内存缓存的数量限制 defaultCache.memoryStorage.config.countLimit = 20 return true }
另外,你的加载代码可以简化,Kingfisher本身提供了更简洁的链式API,不需要手动拆分retrieve和download步骤:
func loadTargetImage(id: String, url: URL) { galleryImageView.kf.setImage( with: url, options: [.cacheOriginalImage] ) { result in switch result { case .success(let value): print("图片加载成功,来源:\(value.cacheType.rawValue)") case .failure(let error): print("图片加载失败:\(error.localizedDescription)") } } }
这样Kingfisher会自动优先从磁盘缓存读取,其次是内存缓存,最后才发起网络请求,且会严格遵守你设置的20张数量限制,超过后自动淘汰最早的缓存文件。
关于直接存Documents目录的问题
你之前直接把图片存到Documents目录确实不是最优方案:一方面系统不会自动清理这个目录的文件,容易导致App占用空间过大;另一方面手动管理缓存的过期、数量限制、命中逻辑会非常繁琐。而Nuke或Kingfisher这类成熟的图片加载框架,已经封装了完善的缓存管理机制,能自动处理缓存清理、持久化、命中策略等问题,远比手动实现高效可靠。
内容的提问来源于stack exchange,提问作者RealNmae




