在UITableViewCell中下载和缓存图像

时间:2017-06-25 05:49:04

标签: ios swift uitableview nscache

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

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

  • 我读过的问题的解决方案是取消<div id="main"> <div id="fixed"></div> </div> 数据请求。但我不知道如何在正确的地方做到这一点 和时间。可能还有其他解决方案,但不确定。

这是我到目前为止所做的:

图片缓存类

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()
    }
}

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

斯威夫特3:

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

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,我们确保我们正在更改其图像的图像视图与图像所针对的行相同。希望它有所帮助!

答案 1 :(得分:3)

有几个问题:

  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
                }
            }
        }
    }
    
  2. 另一个问题是,如果您非常快速地滚动,重用的图像视图可能仍在进行旧的图像检索请求。当你打电话给你的UIImageView类别的异步检索方法时,你应该取消和先前与该单元格相关的请求。

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