我正在 Swift 4 中开发一个图像加载库,例如 Kingfisher带有一些扩展来支持将图像从 URL 加载到 UIImageView 中。
那么我就可以在 UICollection 或 UITableview 单元格上使用这个扩展,并使用如下所示的 UIImageView :
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"collectioncell", for: indexPath)
if let normal = cell as? CollectionViewCell {
normal.imagview.loadImage(fromURL:imageURLstrings[indexPath.row])
}
基本上这是我的扩展代码,实现基本的 URLSession dataTask 和缓存
public extension UIImageView {
public func loadImage(fromURL url: String) {
guard let imageURL = URL(string: url) else {
return
}
let cache = URLCache.shared
let request = URLRequest(url: imageURL)
DispatchQueue.global(qos: .userInitiated).async {
if let data = cache.cachedResponse(for: request)?.data, let
image = UIImage(data: data) {
DispatchQueue.main.async {
self.image = image
}
} else {
URLSession.shared.dataTask(with: request,
completionHandler: { (data, response, error) in
print(response.debugDescription)
print(data?.base64EncodedData() as Any)
print(error.debugDescription)
if let data = data, let response = response, ((response as? HTTPURLResponse)?.statusCode ?? 500) < 300, let image = UIImage(data: data) {
let cachedData = CachedURLResponse(response: response, data: data)
cache.storeCachedResponse(cachedData, for: request)
DispatchQueue.main.async {
self.image = image
}
}
}).resume()
}
}
}
}
结论是,有时我发现如果我的 URL 损坏或出现 404 错误,或者即使我在所有图像完全下载之前滚动 UICollectionView,图像也会加载到错误的单元格中,或者我有时会在 collectionView 中找到重复的图像,但这如果我使用 Kingfisher,则不会发生。
如何防止我的扩展程序将错误的图像加载到单元格中或重复图像?
最佳答案
您正在异步更新 ImageView ,无论 ImageView 是否已被另一个单元格重复使用。
当你开始一个新的 ImageView 请求时,假设你没有立即在缓存中找到图像,那么在开始网络请求之前,你应该 (a) 删除任何先前的图像(就像布兰登建议的那样); (b) 可能加载占位符图像或 UIActivityIndicatorView; (c) 取消对该 ImageView 的任何先前图像请求。只有这样您才可以开始新的请求。
就如何在扩展程序中保存对先前请求的引用而言,您无法添加存储的属性,但可以使用 objc_setAssociatedObject
要在启动 session 时保存 session 任务,请在请求完成时将其设置为 nil
,并且 objc_getAssociatedObject
当检索 session 对象以查看是否需要取消前一个 session 对象时。
(顺便说一句,Kingfisher 将此关联的对象逻辑包装在其 computed property for the task identifier 中。这是保存和检索此任务标识符的好方法。
就失败的请求而言,您执行无限制的图像请求可能会导致该问题。稍微滚动一下,您的请求就会积压并超时。取消(见上文)将减少该问题,但最终仍可能发生。如果修复上述问题后请求仍然失败,那么您可能需要限制并发请求的数量。常见的解决方案是将请求包装在异步 Operation
子类中,并使用 maxConcurrentOperationCount
将它们添加到 OperationQueue
中。或者,如果您正在寻找一种廉价且令人愉快的解决方案,您可以尝试提高请求中的超时阈值。
关于ios - 如何使用 UIImageView Extension 与 Swift 异步加载图像并防止重复图像或错误图像加载到单元格中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56094935/