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

时间:2016-08-26 10:58:38

标签: 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大,所以我将它调整到300px左右。

我知道SDWebImage默认执行强烈的缓存,并使用url的绝对字符串作为其缓存的关键。所以一旦调整大小!我用我调整大小的图像替换原始图像。

问题

一切都按预期正常运作!直到我以低网速测试它,导致图像下载延迟。

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

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

我能想到的解决方案:

  1. 因为sd_setImageWithURL默认使用下载的图像设置imageView的值,而不是使用sd_setImageWithURL下载图像,如果我可以使用下载它,<​​/ p>

    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")
    }
    
  2. 虽然它有效,但只有当我滚动tableView时才会加载图像:(

    问题:

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

    2. 使用SDWebImageManager.sharedManager正在做什么是正确的???是否需要长代码?检查内存缓存然后磁盘缓存并最终调用下载映像并不是太多:o

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

    4. 修改

      我解决了第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相比非常慢。

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

      请帮帮我!!我做错了什么!!在此先感谢:)

1 个答案:

答案 0 :(得分:2)

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

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

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

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

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

<强>更新

如果您使用sd_setImageWithURL,则可以通过UICollectionViewCell子类中的覆盖prepareForReuse()方法防止错误分配图像,并在imageView上调用sd_cancelCurrentImageLoad()并将图像设置为{{1} }。

希望这有帮助。