如何使用UIImageViewExtension与Swift异步加载图像并防止重复图像或错误图像加载到单元格 [英] How to load image asynchronously with Swift using UIImageViewExtension and preventing duplicate images or wrong Images loaded to cells

查看:120
本文介绍了如何使用UIImageViewExtension与Swift异步加载图像并防止重复图像或错误图像加载到单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Swift 4中开发图像加载库,类似于 Kingfisher ,并具有一些扩展名以支持加载图像从URL到UIImageView.

Im developing an image loading library in Swift 4 something like Kingfisher with some extensions to support loading images from URL into an UIImageView .

因此,我可以在具有UIImageView的UICollection或UITableview单元上使用此扩展,如下所示:

So then i can use this extension on a UICollection or UITableview cell with an UIImageView like this :

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: 
  "collectioncell", for: indexPath)

    if let normal = cell as? CollectionViewCell {
    normal.imagview.loadImage(fromURL:imageURLstrings[indexPath.row])
  }

基本上这是我的扩展代码,实现了基本的URLSession dataTask和缓存

Basically this is my extension Code , implementing the basic URLSession dataTask and Caching

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不会发生.

Concluding i found out that sometimes if my URL is broken or i get 404 or even if i scroll the UICollectionView before all the images are completely downloaded, images are loaded into the wrong cell or i sometimes find duplicate images in collectionView but this does not happen if i use Kingfisher.

这是我的结果

这是翠鸟

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

How do i prevent my extension from loading the wrong image into a cell or duplicating images?

推荐答案

您正在异步更新图像视图,无论该图像视图是否已用于其他单元格.

You are asynchronously updating your image view, regardless of whether the image view has been re-used for another cell.

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

When you start a new request for an image view, assuming you didn’t find an image in the cache immediately, before starting network request, you should (a) remove any prior image (like Brandon suggested); (b) possibly load a placeholder image or UIActivityIndicatorView; and (c) cancel any prior image request for that image view. Only then should you start a new request.

关于如何在扩展中保存对先前请求的引用,您无法添加存储的属性,但是可以使用 objc_getAssociatedObject 在检索会话对象时,是否需要取消前一个对象.

In terms of how you save a reference to the prior request in an extension, you can’t add stored properties, but you can use objc_setAssociatedObject to save the session task when you start the session, set it to nil when the request finishes, and objc_getAssociatedObject when retrieving the session object to see if you need to cancel the prior one.

(顺便说一下,Kingfisher将此关联的对象逻辑包装在他们的任务标识符的计算属性.这是保存和检索此任务标识符的一种好方法.

(Incidentally, Kingfisher wraps this associated object logic in their computed property for the task identifier. This is a fine way to save and retrieve this task identifier.

对于失败的请求,您正在执行不受限制的图像请求这一事实可能会导致该问题.滚动一下,您的请求将积压并超时.进行取消(请参见上文)将减少该问题,但最终可能仍会发生.如果在解决上述问题后仍继续使请求失败,则可能需要限制并发请求的数量.常见的解决方案是将请求包装在异步 Operation 子类中,然后使用 maxConcurrentOperationCount 将它们添加到 OperationQueue 中.或者,如果您正在寻找一种便宜又开朗的解决方案,则可以尝试提高请求中的超时阈值.

In terms of failed requests, the fact that you are performing unbridled image requests could cause that problem. Scroll around a bit and your requests will get backlogged and timeout. Doing the cancelation (see above) will diminish that problem, but it might still eventually happen. If you continue to have requests fail after fixing the above, then you might need to constrain the number of concurrent requests. A common solution is to wrap requests in asynchronous Operation subclass and add them to OperationQueue with a maxConcurrentOperationCount. Or if you’re looking for a cheap and cheerful solution, you could try bumping up the timeout threshold in your requests.

这篇关于如何使用UIImageViewExtension与Swift异步加载图像并防止重复图像或错误图像加载到单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆