在 UITableViewCell 中下载和缓存图像 [英] Download and cache images in UITableViewCell

查看:22
本文介绍了在 UITableViewCell 中下载和缓存图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:请不要使用库.这对我来说学习很重要.此外,对此有多种答案,但我发现没有一个能很好地解决问题.请不要标记为重复.提前致谢!

我遇到的问题是,如果您在表格中快速滚动,您会看到旧图像和闪烁.

The problem I have is that if you scroll really fast in the table, you will see old images and flickering.

  • 我阅读的问题的解决方案是取消URLSession数据请求.但我不知道如何在正确的地方做到这一点和时间.可能还有其他解决方案,但不确定.
  • The solution from the questions I read is to cancel the URLSession data request. But I do not know how to do that at the correct place and time. There might be other solutions but not sure.

这是我目前所拥有的:

图片缓存类

class Cache {

    static let shared = Cache()

    private let cache = NSCache<NSString, UIImage>()
    var task = URLSessionDataTask()
    var session = URLSession.shared

    func imageFor(url: URL, completionHandler: @escaping (image: Image? error: Error?) -> Void) {
            if let imageInCache = self.cache.object(forKey: url.absoluteString as NSString)  {
                completionHandler(image: imageInCache, error: nil)
                return
            }

            self.task = self.session.dataTask(with: url) { data, response, error in

                if let error = error {
                    completionHandler(image: nil, error: Error)
                    return
                }

                let image = UIImage(data: data!)

                    self.cache.setObject(image, forKey: url.absoluteString as NSString)
                    completionHandler(image: image, error: nil)
                }

            self.task.resume()
    }
}

使用

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    let myImage = images[indexPath.row]

    if let imageURL = URL(string: myImage.urlString) {
        photoImageView.setImage(from: imageURL)
    }
    return cell
}

有什么想法吗?

推荐答案

几个问题:

  1. 闪烁的一个可能来源是,当您异步更新图像时,您确实想先清除图像视图,因此您看不到重用/出队表格视图单元格前一行的图像.在启动异步图像检索之前,确保将图像视图的 image 设置为 nil.或者,也许将其与您将在许多 UIImageView 同步图像检索类别​​中看到的占位符"逻辑结合起来.

  1. One possible source of flickering is that while you're updating the image asynchronously, you really want to clear the image view first, so you don't see images for prior row of reused/dequeued table view cell. Make sure to set the image view's image to nil before initiating the asynchronous image retrieval. Or, perhaps combine that with "placeholder" logic that you'll see in lots of UIImageView sync image retrieval categories.

例如:

extension UIImageView {

    func setImage(from url: URL, placeholder: UIImage? = nil) {
        image = placeholder               // use placeholder (or if `nil`, remove any old image, before initiating asynchronous retrieval

        ImageCache.shared.image(for: url) { [weak self] result in
            switch result {
            case .success(let image):
                self?.image = image

            case .failure:
                break
            }
        }
    }
}

  • 另一个问题是,如果你滚动得非常快,重用的图像视图可能有一个仍在进行中的旧图像检索请求.您确实应该,当您调用 UIImageView 类别的异步检索方法时,您应该取消与该单元格关联的先前请求.

  • The other issue is that if you scroll very quickly, the reused image view may have an old image retrieval request still in progress. You really should, when you call your UIImageView category's async retrieval method, you should cancel and prior request associated with that cell.

    这里的技巧是,如果您在 UIImageView 扩展中执行此操作,则不能仅创建新的存储属性来跟踪旧请求.因此,您经常使用关联值"来跟踪先前的请求.

    The trick here is that if you're doing this in a UIImageView extension, you can't just create new stored property to keep track of the old request. So you'd often use "associated values" to keep track of prior requests.

    这篇关于在 UITableViewCell 中下载和缓存图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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