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

标签 ios swift image sdwebimage

概览

我在我的 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. 为什么我的第二种方法在下载后不加载图像并期望 Collection View 滚动并重新加载单元格以显示图像?

编辑

我解决了第三个问题:)对不起我的错误。我正在比较 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 相比,现在图像下载速度非常慢。

有什么方法可以使用 method1 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() 方法并调用 sd_cancelCurrentImageLoad() 在 imageView 上并将图像设置为 nil

希望这对您有所帮助。

关于ios - SDWebImage 的 sd_setImageWithURL 在滚动时用图像更新了错误的单元格!!这是预期的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39164701/

相关文章:

iphone - iOS 中的四点渐变

ios - Activity 指示器 webView Xcode 5 IOS 7

ios - 企业应用单应用模式并不总是自动启动

swift - 在 Firebase 中获取文档,其中字段在 Swift 4 中为 X

python - 将给定 URL 的 Jpeg 图像下载到 numpy 数组中

php - 高级 PHP 图像共享。从数据库到 Facebook 墙?

javascript - 通过表单传递base64编码的图像

ios - 如何在后台模式下运行 NStimer?

ios - 完成处理程序不返回任何内容,即使它看起来像在单步执行时一样

ios - CGRect.offsetBy 不工​​作