如何使用 UIImageViewExtension 与 Swift 异步加载图像并防止重复图像或错误图像加载到单元格

Posted

技术标签:

【中文标题】如何使用 UIImageViewExtension 与 Swift 异步加载图像并防止重复图像或错误图像加载到单元格【英文标题】:How to load image asynchronously with Swift using UIImageViewExtension and preventing duplicate images or wrong Images loaded to cells 【发布时间】:2019-09-29 09:16:16 【问题描述】:

我正在 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 数据任务和缓存

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,则不会发生。

This is my results

This is kingfishers

如何防止我的扩展程序将错误的图像加载到单元格中或复制图像?

【问题讨论】:

@rob 你能帮我吗? ***.com/questions/57137326/… 【参考方案1】:

您正在异步更新您的图像视图,无论该图像视图是否已被重新用于另一个单元格。

当您开始对图像视图的新请求时,假设您没有立即在缓存中找到图像,在开始网络请求之前,您应该 (a) 删除任何先前的图像(如 Brandon 建议的那样); (b) 可能加载占位符图像或UIActivityIndicatorView; (c) 取消对该图像视图的任何先前图像请求。只有这样你才能开始一个新的请求。

关于如何在扩展中保存对先前请求的引用,不能添加存储属性,但是可以在启动会话时使用objc_setAssociatedObject保存会话任务,将其设置为@987654327 @ 请求完成时,objc_getAssociatedObject 检索会话对象时查看是否需要取消前一个。

(顺便说一句,Kingfisher 将这个关联的对象逻辑包装在他们的 computed property for the task identifier 中。这是保存和检索此任务标识符的好方法。


就失败的请求而言,您正在执行肆无忌惮的图像请求这一事实可能会导致该问题。滚动一下,您的请求将被积压并超时。取消(见上文)会减少这个问题,但它可能最终还是会发生。如果您在修复上述问题后仍然有请求失败,那么您可能需要限制并发请求的数量。一个常见的解决方案是将请求包装在异步Operation 子类中,并将它们添加到OperationQueuemaxConcurrentOperationCount。或者,如果您正在寻找一种便宜且令人愉快的解决方案,您可以尝试提高请求中的超时阈值。

【讨论】:

删除任何像 Brandon 建议的先前图像不足以解决问题,我不知道他为什么删除他的答案,但是我能够跟踪会话对象并取消任何先前的任务你的建议确实解决了问题,谢谢。 Brandon 的观察是解决方案的重要组成部分(如果您不立即重置图像,您可能会在检索新图像时暂时看到旧图像),但正如您发现的那样,它只是整个解决方案的一小部分。 我确实点击了复选标记,我收到了这样的回复“感谢您的反馈!声望低于 15 人的投票将被记录,但不要更改公开显示的帖子分数。” link@Rob 有什么帮助吗? @big fire 你能在问题解决后分享代码吗,因为我在这里遇到了类似的问题图像重复或错误的图像加载

以上是关于如何使用 UIImageViewExtension 与 Swift 异步加载图像并防止重复图像或错误图像加载到单元格的主要内容,如果未能解决你的问题,请参考以下文章

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?