[英]Kingfisher image render recycling cells
我正在使用 Kingfisher 下载和缓存我的图像。 我正在使用 CustomImageView 下面的自定义类,它扩展了 ImageView。 我还使用我的自定义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 上看到并尝试过的解决方案:
当您快速滚动时,您正在重用单元格。 重用的单元格包含 KF 图像,这些图像可能有一个正在运行的下载任务(从调用 kf.setImage 开始),用于回收文章中的图像。 如果允许该任务完成,它将使用旧图像更新您的新单元格。 我将建议两种方法来解决它。
请参阅 Kingfisher 备忘单, 取消下载任务。
备忘单显示了如何在表视图的 didEndDisplaying 中停止这些任务。 我在这里引用:
// In table view delegate
func tableView(_ tableView: UITableView, didEndDisplaying cell:
UITableViewCell, forRowAt indexPath: IndexPath) {
//...
cell.imageView.kf.cancelDownloadTask()
}
你可以在那里或在你的单元类中的 didSet 观察者中做到这一点。 你明白了。
另一种方法是允许下载任务完成,但仅当下载的 URL 与当前所需的 URL 匹配时才更新单元格图像。 也许您试图用 lastUrlLoaded 实例变量做类似的事情。
你在 kf.setImage 的完成处理程序中有这个:
if url.absoluteString != self.lastUrlLoaded { return }
这就是我的意思,除非您没有正确设置该变量以使其工作。 为了便于解释,让我们假设它被称为“desiredURL”。 然后你可以在 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 为您所做的困难方式,即加载缓存等。我相信您有这样做的原因,无论哪种方式,您仍然需要处理这个问题问题。
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
}
在您的模型中检查 url 是否不存在将其设置为 nil,然后在单元格中检查您的 url 是否存在设置它的图像,否则设置一个占位符。
if article?.image_url != nil{
_image.kf.indicatorType = .activity
_image.loadImage(url: image_url, type: "news")
}else{
_image = UIImage(named: "placeholder")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.