在UITableViewCell中下载和caching图像

注意:请不要图书馆。 这对我学习很重要。 另外,这里有各种各样的答案,但我没有find解决这个问题很好。 请不要标记为重复。 提前致谢!

我遇到的问题是,如果您在桌面上滚动速度非常快,您将看到旧图像和闪烁。

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

这是我迄今为止:

图像caching类

 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. 闪烁的一个可能的来源是,当你更新图像asynchronous,你真的想要清除图像视图,所以你没有看到图像重复使用/出列表视图单元格的前一行。 确保在启动asynchronous图像检索之前将图像视图的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 } } } } 
  2. 另一个问题是,如果您快速滚动,重用的图像视图可能会有一个旧的图像检索请求仍在进行中。 当您调用UIImageView类别的asynchronous检索方法时,您应该确实应该取消与该单元关联的事先请求。

    这里的技巧是,如果你在UIImageView扩展中这样做,你不能创build新的存储属性来跟踪旧的请求。 所以你经常使用“关联值”跟踪以前的请求。

Swift 3:

通过这种方式可以避免闪烁:

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell使用下面的代码public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

 cell.photoImageView.image = nil //or keep any placeholder here cell.tag = indexPath.row let task = URLSession.shared.dataTask(with: imageURL!) { data, response, error in guard let data = data, error == nil else { return } DispatchQueue.main.async() { if cell.tag == indexPath.row{ cell.photoImageView.image = UIImage(data: data) } } } task.resume() 

通过检查cell.tag == indexPath.row ,我们确保imageview的图像我们正在改变,是图像的意图是相同的行。 希望能帮助到你!