iOS:SDWebImage使用不正确的图像加载单元格

时间:2015-01-28 17:22:22

标签: ios iphone sdwebimage

我正在使用SDWebImage为我的表格单元格加载图片,使用以下代码:

[cell.coverImage sd_setImageWithURL:[self.dataInJSONModel.Content[indexPath.row] CoverImage] placeholderImage:[UIImage imageNamed:@"imageplaceholder_general"]];

问题是当我向上和向下滚动时,图像被插入到错误的单元格中。在阅读StackOverflow上有关此问题的一些帖子后,我怀疑这是因为我们滚动时会重复使用单元格,因此可以将图像的异步下载放置在已更改的单元格索引路径上。

因此我实施了一些改变,例如:

SDWebImageManager *manager = [SDWebImageManager sharedManager];
UIImageView * cellCoverImage = cell.coverImage;
[manager downloadImageWithURL:[self.dataInJSONModel.Content[indexPath.row] CoverImage] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL * oriURL) {

      NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
      if ([visibleIndexPaths containsObject:indexPath]) {

          cellCoverImage.image = image;
       }
   }]; 

甚至比较网址:

SDWebImageManager *manager = [SDWebImageManager sharedManager];
UIImageView * cellCoverImage = cell.coverImage;
[manager downloadImageWithURL:[self.dataInJSONModel.Content[indexPath.row] CoverImage] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL * oriURL) {

   if([oriURL isEqual:[self.dataInJSONModel.Content[indexPath.row] CoverImage]])
    {
        cell.coverImage.image = image;

    }

 }];

问题仍然存在。或者我可能错误地编程了它?在网上找到了一些建议,但还没有找到具体的解决方案。

需要帮助!

修改

我已经对它进行了一些更改但仍然不起作用:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

NewsFeedCell * cell = [tableView dequeueReusableCellWithIdentifier:@"NewsFeedCell" forIndexPath:indexPath];


if (self.dataInJSONModel)
{
   cell.coverImage.image = nil;
    SDWebImageManager *manager = [SDWebImageManager sharedManager];
    [manager downloadImageWithURL:[self.dataInJSONModel.Content[indexPath.row] CoverImage] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL * oriURL) {

        if ([cell isEqual:[self.tableView cellForRowAtIndexPath:indexPath]])
        {
            cell.coverImage.image = image;
        }

    }];

}

5 个答案:

答案 0 :(得分:3)

我遇到了同样的问题,并尝试分配.image = nil,但不能正常工作。

最后,我的意思是使用取消操作覆盖UITableViewCell中的prepareForReuse:

- (void)prepareForReuse  
{
    [super prepareForReuse];
    [_imageView sd_cancelCurrentImageLoad];
}

答案 1 :(得分:2)

在SDWebImage Github页面上发布了问题并得到了解决我问题的人的建议!我只是在我的单元格的实现文件中覆盖prepareForReuse方法,并使受影响的imageView的图像无效。

未来读者的示例代码:

In my NewsFeedCell.m
- (void) prepareForReuse
{
    [super prepareForReuse];

    self.coverImage.image = NULL;

}

这解决了这个问题!我在GitHub上打开的问题是https://github.com/rs/SDWebImage/issues/1024,如果你们有人想看到的话。

答案 2 :(得分:1)

我尝试了大部分这些解决方案,花了一些时间来解决这个问题。我有2个解决方案适合我。

  • 在单元格中将图像设置为ImageView时停止下载。

cellForRow 中添加以下内容:

cell.imageView.sd_cancelCurrentImageLoad()

然后在单元格中:

func prepareForReuse() {
     imageView.image = UIImage.placeholderImage() // or nill
}

这不是真正的解决方案,因为您实际停止了图像下载并浪费了已下载的数据。

  • 另一个更优雅的解决方案是为 UIImageView 添加扩展

选择适合您的动画,然后尝试:

func setImageAnimated(imageUrl:URL, placeholderImage:UIImage) {
    self.sd_setImage(with: imageUrl, placeholderImage: placeholderImage , options:SDWebImageOptions.avoidAutoSetImage, completed: { (image, error, cacheType, url) in
        if cacheType == SDImageCacheType.none {
            UIView.transition(with: self.superview!, duration: 0.2, options:  [.transitionCrossDissolve ,.allowUserInteraction, .curveEaseIn], animations: {
                self.image = image
            }, completion: { (completed) in
            })
        } else {
            self.image = image
        }
    })
}

答案 3 :(得分:0)

你对问题的分析是正确的,只是没有正确地执行它。

cellForRowAtIndexPath的一些伪代码......

 - set the cell.imageView.image to nil to wipe out 
                previous use of cell image view contents
 - get the URL from data source
 - initiate asynchronous download with completion ^{
      //check the cell is still the correct cell
      if ([cell isEqual: [collectionView cellForRowAtIndexPath:indexPath]]) {
            cell.imageView.image = image
      }
 }

你做错了几件事 - 在您知道需要之前(在完成块中),不要获取对单元格图像视图的引用 - 不检查visibleIndexPaths,indexPath可能仍然可见但分配给不同的单元格(例如,如果已滚动然后再打开)。我在这里使用的'cell isEqual'技术应该足以满足所有情况。

您还可以通过覆盖单元格-prepareForReuse方法来为循环单元格找出旧单元格内容。

答案 4 :(得分:0)

这里的明显错误是你没有考虑使用Blocks。本质上,完成发生在后台线程上,所有UI更新必须发生在主线程上。

简单的解决方案是;

   dispatch_async(dispatch_get_main_queue(), ^{
      cell.coverImage.image = image;
   });

此外,如果您打算在完成块中引用tableView,则应使用弱引用。