一尘不染

在UITableViewCell中下载和缓存图像

swift

注意:请没有库。 这对我来说很重要。另外,对此有各种各样的答案,但我发现没有一个能很好地解决该问题。请不要将其标记为重复项。提前致谢!

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

  • 我所读问题的解决方案是取消URLSession 数据请求。但是我不知道如何在正确的时间和地点做到这一点。可能还有其他解决方案,但不确定。

这是我到目前为止的内容:

图像缓存类

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
}

有什么想法吗?


阅读 254

收藏
2020-07-07

共1个答案

一尘不染

几个问题:

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

例如:

    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
            }
        }
    }
}
  1. 另一个问题是,如果您快速滚动,则重用的图像视图可能仍在进行旧的图像检索请求。实际上,当您调用UIImageView类别的异步检索方法时,应该取消与该单元格关联的先前请求。

这里的窍门是,如果在UIImageView扩展中执行此操作,则不能仅创建新的存储属性来跟踪旧请求。因此,您通常会使用“关联值”来跟踪先前的请求。

2020-07-07