Swift 3图片缓存问题:滚动时图片重复下载如何解决?
解决图片重复下载的缓存逻辑修复方案
兄弟,你的问题核心在于缓存检查的顺序完全搞反了!你现在是先发起网络请求,等下载完才去看缓存——这等于每次调用updateUI都会先触发下载,缓存根本没起到拦截作用,难怪滚动时一直重复下载。
我帮你梳理下问题点,再给出修复后的代码:
原代码的核心问题
- 缓存检查时机错误:网络请求发起后才检查缓存,等于白做缓存,每次都会先请求网络
- 强制解包风险:
imageToCache!如果图片数据转UIImage失败,会直接崩溃 - 缓存Key不严谨:用
thumbnailURL as AnyObject作为Key,Swift的String是值类型,桥接成AnyObject不够稳定 - 未处理循环引用:网络回调里直接用
self,可能导致内存泄漏
修复后的完整代码
var episode: Product! { didSet { self.updateUI() } } // 优化NSCache类型,指定Key为NSString,Value为UIImage,更严谨 let imageCache = NSCache<NSString, UIImage>() func updateUI() { // 先更新文本类UI,避免复用旧数据 menuItemNameLabel?.text = episode.title ingredientsItemLabel?.text = episode.summary priceItemLabel?.text = episode.price // 设置默认占位图 menuItemImageView?.image = UIImage(named: "Koulourades") guard let thumbnailURLStr = episode.thumbnailURL else { return // 如果没有图片URL,直接返回 } // 把URL字符串转为NSString,作为缓存的Key(NSCache更适合用引用类型当Key) let cacheKey = thumbnailURLStr as NSString // 第一步:优先检查缓存! if let cachedImage = imageCache.object(forKey: cacheKey) { menuItemImageView?.image = cachedImage return // 有缓存直接显示,不用发起网络请求 } // 没有缓存才发起网络请求 let networkService = NetworkService(url: thumbnailURLStr) // 用[weak self]避免循环引用 networkService.downloadImage { [weak self] imageData in guard let self = self, let validData = imageData else { return // 处理self已释放或数据为空的情况 } // 回到主线程更新UI DispatchQueue.main.async { guard let imageToCache = UIImage(data: validData) else { // 图片转失败时,保持占位图,也可以加错误提示 return } // 存入缓存 self.imageCache.setObject(imageToCache, forKey: cacheKey) // 显示图片 self.menuItemImageView?.image = imageToCache } } }
关键修改点解释
- 缓存检查前置:现在进入
updateUI后第一时间检查缓存,有缓存直接显示,彻底避免重复请求 - 弱引用self:防止网络回调时ViewController被强引用导致内存泄漏
- 安全的可选值处理:去掉所有强制解包,转图片失败时不会崩溃,容错性更强
- 严谨的缓存Key:用NSString作为NSCache的Key,比AnyObject更稳定,避免桥接问题
额外优化建议(可选)
如果你的图片是在TableView/CollectionView的Cell里使用,建议再加个请求取消逻辑:当Cell被复用时,取消之前未完成的图片请求,避免无用的网络请求浪费资源。当然,如果不想自己写这么多逻辑,也可以直接用成熟的第三方库(比如Kingfisher、SDWebImage),它们已经帮你封装好了缓存、请求取消、错误处理等所有逻辑。
内容的提问来源于stack exchange,提问作者Panagiotis Goutzianas
相关产品推荐
相关产品推荐

