翠鸟图像渲染回收细胞

时间:2017-11-09 04:21:02

标签: ios swift uitableview uicollectionviewcell kingfisher

我正在使用Kingfisher下载并缓存我的图像。我正在使用扩展ImageView的CustomImageView下面的自定义类。我也使用我的自定义 UITableViewCell 来调用CustomCell类文件中 didSet 属性中的loadImage方法。

以下方法loadImage是所有魔法发生的地方。

class CustomImageView : UIImageView {
var lastUrlLoaded: String?

func loadImage(url:String) {
    lastUrlLoaded = url
    ImageCache.default.retrieveImage(forKey: url, options: nil) { (image, cacheType) in
        if let image = image {
            self.image = image
            return
        }
        else {
            guard let url = URL(string: url) else { return }
            self.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: nil) {
                (image, error, cacheTye, _) in
                if let err = error {
                    self.kf.indicatorType = .none
                    DispatchQueue.main.async {
                      self.image = #imageLiteral(resourceName: "no_image_available") 
                    }
                    print ("Error loading Image:", err)
                    return
                }

                if url.absoluteString != self.lastUrlLoaded { return }
                if let image = image {
                    ImageCache.default.store(image, forKey: url.absoluteString)
                    DispatchQueue.main.async {
                        self.image = image
                    }
                }
            }
        }
    }
}

// Custom TableViewCell -- NewsCell.file
 class NewsCell: UITableViewCell {
var article: Article? {
    didSet{
        guard let image_url = article?.image_url else { return }
        _image.kf.indicatorType = .activity
        _image.loadImage(url: image_url, type: "news")
      }
   }
}

 // METHOD in my NewsController
 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: 
  IndexPath) -> UITableViewCell {        
   let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! NewsCell
      cell.article = articles[indexPath.item]
return cell
}

我在快速滚动单元格时出现问题,一些已加载的图像正用于错误的单元格。我研究过并阅读了其他帖子,但没有答案对我有所帮助。我理解它正在处理后台任务,但只是不确定如何解决它。如果有人可以帮助或指出我正确的方向,那将非常感激。

我在stackoverflow上看过的解决方案并尝试过:

  1. 自定义单元格中的prepareForReuse将图像设置为nil。
  2. 在cellforrowatindexpath上将图像设置为nil。

3 个答案:

答案 0 :(得分:4)

问题

快速滚动时,您正在重复使用单元格。重用的单元格包含KF图像,其可以具有运行的下载任务(从对kf.setImage的调用开始),用于再循环文章中的图像。如果允许该任务完成,它将使用旧图像更新您的新单元格。我会建议两种方法来解决它。

答案1 - 终止循环下载任务

请参阅Kingfisher备忘单,Canceling a downloading task

备忘单显示了如何在表格视图的didEndDisplaying中停止这些任务。我在这里引用它:

// In table view delegate
func tableView(_ tableView: UITableView, didEndDisplaying cell: 
UITableViewCell, forRowAt indexPath: IndexPath) {
    //...
    cell.imageView.kf.cancelDownloadTask()
}

您可以在那里或在您的单元格类中的didSet观察者中执行此操作。你明白了。

答案2 - 不要杀死他们,只是忽略结果

另一种方法是允许下载任务完成,但只有在下载的URL与当前所需的URL匹配时才更新单元格图像。也许你试图用你的lastUrlLoaded实例变量做类似的事情。

你在kf.setImage的完成处理程序中有这个:

if url.absoluteString != self.lastUrlLoaded { return }

这就是我的意思,除非您没有正确设置该变量以使其正常工作。让我们想象它被称为" wantURL"相反,为了解释。然后你可以在didSet观察者中设置它:

_image.desiredURL = image_url

在kf.setImage的完成处理程序中测试它:

// phew, finished downloading, is this still the image that I want?
if url != self.desiredURL { return }

备注

如果是我,我肯定会采用第二种方法(它具有缓存下载图像的积极副作用,但我也不相信取消任务)。

此外,您似乎正在尝试kf.setImage为您所做的事情,即加载缓存等。我确定您有理由,无论哪种方式,您仍然会需要处理这个问题。

答案 1 :(得分:3)

override func prepareForReuse() {
    super.prepareForReuse()
    imageView.kf.cancelDownloadTask() // first, cancel currenct download task
    imageView.kf.setImage(with: URL(string: "")) // second, prevent kingfisher from setting previous image
    imageView.image = nil
}

答案 2 :(得分:0)

在模型中检查URL是否不存在,将其设置为nil,然后在单元格中检查URL是否存在,将其设置为图像,否则为其设置一个占位符。

if article?.image_url != nil{
  _image.kf.indicatorType = .activity
  _image.loadImage(url: image_url, type: "news")
}else{
  _image = UIImage(named: "placeholder")
}