滚动快速滚动时,错误的图像异步加载在UitableView-cell中



我有一个带有用户列表及其个人资料图片的Uitable-view。我正在加载图片(http://api/pictures/{userId}),每个播放器异步:

func loadImageAsync(imageUrl: URL, completionHandler handler: @escaping (_ success: Bool, _ image: UIImage?) -> Void){
DispatchQueue.global(qos: .userInitiated).async { () -> Void in
    if let imgData = try? Data(contentsOf: imageUrl), let img = UIImage(data: imgData) {
        DispatchQueue.main.async(execute: { () -> Void in
            handler(true, img)
        })
    } else {
        handler(false, nil)
    }
}

在Cellforrowat-Index-Fuction的完成处理程序中,我正在设置图片。

       loadImageAsync(imageUrl: imageUrl!, label: ip) { (success, image, backlabel) -> Void in
            if(success){
                cell.profilePictureView.image = image
            }
        }

但是,当我快速滚动时,有些图片会加载在错误的单元格中。为了防止重复使用,我正在"重复使用"后"重置"图像视图:

    override func prepareForReuse() {
        profilePictureView.image  = UIImage(named: "defaultProfilePicture")
    }

但是,为什么还要快速滚动时仍然有些图像false?

嗯,这也是我的想法。

__更新:因此,我使用标签参数(键入Any)扩展了该功能,该参数被放入功能中时会返回。我试图将参数(用于indexpath)与当前的indexpath进行比较。实际上,这应该有效 - 不是吗?!

            loadImageAsync(imageUrl: imageUrl!, label: ip) { (success, image, backlabel) -> Void in
            cell.loader.stopAnimating()
            if (backlabel as! IndexPath == indexPath) {
                //set image...

但是,它没有任何效果。您知道为什么或还有其他解决方案可以解决此问题吗?

问题是,如果您快速滚动,下载可能会花费足够长的时间,以至于到完成时,所讨论的单元格已经从屏幕上滚下来,并已回收为不同的Indexpath您的数据模型。

诀窍是在完成块中的该indexpath处向单元格询问表视图,仅在收回单元格时才安装图像:

   loadImageAsync(imageUrl: imageUrl!, label: ip, for indexPath: IndexPath) { (success, image, backlabel) -> Void in
        if(success){
            let targetCell = tableview.cell(for: indexPath)
            targetCell.profilePictureView.image = image
        }
    }

编辑:

重新定义您的loadImageasync函数:

func loadImageAsync(imageUrl: URL,
  indexPath: IndexPath, 
  completionHandler handler: @escaping (_ success: Bool, 
    _ image: UIImage?,
    _ indexPath: IndexPath ) -> Void) { ... }

编辑#2

,顺便说一句,您应该真正保存图像来磁盘并从那里加载它们,而不是每次从Internet加载。我建议将图像URL的哈希作为文件名。

修改loadImageasync如下:

  1. 检查文件是否已经存在于磁盘上。如果是这样,请加载并返回。

  2. 如果文件不存在,请执行异步加载,然后在返回内存映像之前,将其保存到磁盘上。

,因为在为下一个用户重复使用单元格之后,可以调用您的完整汉格勒,并且可能已经触发了单元格的另一个图像请求。事件的顺序(重复/完成)是无法预测的,实际上,以后的异步请求可以在较早的一个请求之前完成。

最新更新