SDWebImage 的 sd_setImageWithURL 在滚动时用图像更新了错误的单元格!!这是预期的行为吗?

SDWebImage's sd_setImageWithURL updates the wrong cell with Image on scrolling!! Is that a expected behaviour?

俯视图

我在我的 collectionView 单元格中使用 SDWebImage 从 Web 服务器下载图像。

if floor.hasTitleImage != nil {
            self.floorImageView.sd_setImageWithURL(NSURL(string:(floor.hasTitleImage?.imageURL)!), placeholderImage: UIImage(named: "Placeholder"), completed: { (imageDownloaded, error, cacheType, url) in
                if imageDownloaded.size.width > 300 {
                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
                        let resizedImage = imageDownloaded.resizePreservingAspectRatio(toSize: CGSize(width: 300, height: 300))
                        SDImageCache.sharedImageCache().removeImageForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, fromDisk: true, withCompletion: {
                            SDImageCache.sharedImageCache().storeImage(resizedImage, forKey: NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, toDisk: true)
                        })
                    })
                }
            })
        }
        else{
            self.floorImageView.image = UIImage(named: "Placeholder")
        }

现在这段代码正在做的是使用存储在名为 floor 的核心数据元素中的 url 下载图像。现在下载的图像比我的 ImageView 大得多,所以我将它的大小调整到 300 像素左右。

我知道 SDWebImage 默认情况下会进行密集缓存,并使用 url 的绝对字符串作为其缓存的关键字。所以一旦调整大小!我用调整后的图片替换了原始图片。

问题

一切如预期般顺利!直到我用低网速测试它导致图像下载延迟。

如果图片下载需要时间,直到那时如果我滚动 tableView 并且单元格被重复使用,一旦下载了图片,SDWebImage 加载单元格的 imageView 但最终导致错误的单元格和错误的图像。

虽然这种情况只发生一次,但下次将从缓存中加载图像,一切正常。但这是预期的行为还是我做错了什么???

我能想到的解决方案:

  1. 因为 sd_setImageWithURL 默认情况下使用下载的图像设置 imageView 的值而不是使用 sd_setImageWithURL 下载图像,如果我可以使用

    下载图像
    if floor.hasTitleImage != nil {
        if let downloadedImage = SDImageCache.sharedImageCache().imageFromMemoryCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString){
            self.floorImageView.image = downloadedImage
        }
        else if let diskImage = SDImageCache.sharedImageCache().imageFromDiskCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString){
            self.floorImageView.image = diskImage
        }
        else{
            let downloadManager = SDWebImageManager.sharedManager();
            downloadManager.downloadImageWithURL(NSURL(string:(floor.hasTitleImage?.imageURL)!), options: [], progress: nil, completed: { (downloadedImage, error, cacheType, finished, url) in
                if downloadedImage.size.width > 300 {
                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
                        let resizedImage = downloadedImage.resizePreservingAspectRatio(toSize: CGSize(width: 300, height: 300))
                        SDImageCache.sharedImageCache().removeImageForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, fromDisk: true, withCompletion: {
                            SDImageCache.sharedImageCache().storeImage(resizedImage, forKey: NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString, toDisk: true)
                        })
                        if floor.hasTitleImage?.imageURL != nil && floor.hasTitleImage?.imageURL! == url{
                            dispatch_async(dispatch_get_main_queue(), {
                                self.floorImageView.image = SDImageCache.sharedImageCache().imageFromMemoryCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString)
                                self.reloadInputViews()
                            })
                        }
                    })
                }
            })
        }
    }
    else{
        self.floorImageView.image = UIImage(named: "Placeholder")
    }
    

虽然它有效,但它只会在我滚动 tableView 时加载图像:(

问题:

  1. sd_setImageWithURL 所做的是预期的行为吗??我的意思是每一个使用带有 tableView 或 CollectionView 的 SDWebImage 的应用程序都必须面对这个正确的?所以如果没有人面对它,我一定是做错了什么:(我做错了什么吗?

  2. 我用SDWebImageManager.sharedManager做什么是正确的???需要那么长的代码吗?检查内存缓存,然后检查磁盘缓存,最后调用下载图像是不是太多了:o

  3. 为什么我的第二种方法在下载后不加载图像并期望集合视图滚动并重新加载单元格以显示图像??

编辑

我解决了第三个问题:)对不起我的错误。我在比较 if floor.hasTitleImage?.imageURL != nil && floor.hasTitleImage?.imageURL! == url{ 这是错误的,因为上面的 url 是 NSURL 而 floor.hasTitleImage?.imageURL!是 NSString.

所以更新的解决方案:

if floor.hasTitleImage?.imageURL != nil && floor.hasTitleImage!.imageURL! == url.absoluteString{
                                dispatch_async(dispatch_get_main_queue(), {
                                    self.floorImageView.image = SDImageCache.sharedImageCache().imageFromDiskCacheForKey(NSURL(string:(floor.hasTitleImage?.imageURL)!)?.absoluteString)
                                    self.setNeedsLayout()
                                })
                            }

尽管我的第二种方法现在下载图像并正确更新单元格,但与 sd_setImageWithURL 相比,现在图像下载速度非常慢。

有什么方法可以使用方法 1 sd_setImageWithURL 并正确更新图像?

请帮帮我!!做错了什么!提前致谢:)

  1. Is what sd_setImageWithURL doing is expected behaviour ?? I mean every single one of the app using SDWebImage with tableView or CollectionView must have faced this correct ?? So if no body faced it I must be doing something wrong :( Am I doing anything wrong ?

不,这不是预期的行为。我正在使用 SDWEbImage 以及 tableView 和 collectionView,两者都工作正常。

  1. Is what am doing using SDWebImageManager.sharedManager is correct ??? Is that long code required? Checking memory cache then disk cache and finally making call to download image isn't it too much :o

您不必自己缓存图像,SDWebImage 会为您处理缓存过程(在内存和磁盘中)。

如果您需要在缓存和显示之前调整图像大小,我认为最好通过工具 SDWebImageManagerDelegate 来实现,它允许您在图像下载之后但在缓存和显示之前转换图像。

更新:

如果您使用 sd_setImageWithURL,还有另一种防止错误分配图像的解决方案是通过重写 UICollectionViewCell 子类中的 prepareForReuse() 方法并在 imageView 上调用 sd_cancelCurrentImageLoad() 并将图像设置为 nil.

希望对您有所帮助。