Swift 5用URLSession实现tableView图片缓存及代码报错解决
错误原因分析
- 错误1、错误3的根源是
NSCache泛型参数使用错误:NSCache<KeyType, ObjectType>的第一个参数是缓存键的类型,第二个是缓存对象的类型,你的代码写反了两个参数的顺序;同时NSCache要求键必须是继承自NSObject的类类型,Swift原生String是结构体类型,不满足要求,所以触发类类型要求报错。 - 错误2的根源是
NSCache不支持Swift下标语法直接赋值/取值,只能用官方提供的setObject(_:forKey:)存、object(forKey:)取。 - 额外隐含问题:你把
imageCache定义在configure函数内部,每次调用函数都会新建缓存实例,完全无法实现缓存复用的效果,需要把缓存放到函数外部全局复用。
修正后代码
// 缓存放到函数外部,比如作为当前UITableViewCell类的静态属性,保证全局复用 static let imageCache = NSCache<NSString, UIImage>() func configure(with urlString: String, name: String, address: String, station: String) { loader.startAnimating() loader.isHidden = false locationImageView.image = nil // 清空旧图片,避免cell复用出现图片错乱 // 优先查缓存,命中就直接返回不用走网络请求 if let cachedImage = Self.imageCache.object(forKey: urlString as NSString) { self.locationImageView.image = cachedImage self.nameLabel.text = name self.addressLabel.text = address self.loader.stopAnimating() self.loader.isHidden = true return } guard let url = URL(string: urlString) else { loader.stopAnimating() loader.isHidden = true return } let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in guard let data = data, error == nil, let locationImage = UIImage(data: data) else { DispatchQueue.main.async { self?.loader.stopAnimating() self?.loader.isHidden = true } return } // 存入缓存,将String转成NSString满足类类型要求 Self.imageCache.setObject(locationImage, forKey: urlString as NSString) DispatchQueue.main.async { self?.nameLabel.text = name self?.addressLabel.text = address self?.locationImageView.image = locationImage self?.loader.stopAnimating() self?.loader.isHidden = true } } task.resume() }
额外优化说明
- 增加了cell复用防护,避免UITableView滑动时出现旧图片闪烁的问题
- 增加了缓存命中逻辑,重复加载同一张图片时不会重复发起网络请求
- 去掉了原图的强制解包逻辑,避免无效图片数据导致的崩溃
内容的提问来源于stack exchange,提问作者jo1
相关产品推荐
相关产品推荐

