我正在Swift 4中开发图像加载库,类似于Kingfisher,并具有一些扩展功能以支持将URL中的图像加载到UIImageView中。
因此,我可以在具有UIImageView的UICollection或UITableview单元格上使用此扩展:
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不会发生。
如何防止扩展程序将错误的图像加载到单元格中或复制图像?
答案 0 :(得分:1)
您正在异步更新图像视图,无论该图像视图是否已用于其他单元格。
当您开始新的图像视图请求时,假设您没有立即在缓存中找到图像,那么在开始网络请求之前,您应该(a)删除任何先前的图像(如Brandon建议的那样); (b)可能会加载一个占位符图像或UIActivityIndicatorView
; (c)取消对该图像视图的任何先前图像请求。只有这样,您才可以开始新的请求。
关于在扩展中保存对先前请求的引用的方式,您无法添加存储的属性,但是可以在启动会话时使用objc_setAssociatedObject
保存会话任务,将其设置为请求完成时,nil
,检索会话对象时,objc_getAssociatedObject
,以查看是否需要取消前一个对象。
(顺便说一下,Kingfisher将此关联的对象逻辑包装在它们的computed property for the task identifier中。这是保存和检索此任务标识符的一种好方法。
对于失败的请求,您正在执行不受限制的图像请求这一事实可能会导致该问题。滚动一下,您的请求将积压并超时。进行取消(请参见上文)将减少该问题,但最终可能仍会发生。如果在解决上述问题后仍继续使请求失败,则可能需要限制并发请求的数量。一种常见的解决方案是将请求包装在异步Operation
子类中,然后使用OperationQueue
将它们添加到maxConcurrentOperationCount
中。或者,如果您正在寻找一种便宜又开朗的解决方案,则可以尝试提高请求中的超时阈值。