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

问题描述 投票:0回答:5

我目前正在使用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;
        }

    }];

}
ios iphone sdwebimage
5个回答
3
投票

我遇到了同样的问题,并尝试分配.image = nil,但没有工作。

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

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

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,如果你们有人想看到的话。


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
        }
    })
}

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方法来为循环细胞排除旧细胞内容。


0
投票

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

简单的解决方案是;

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

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

© www.soinside.com 2019 - 2024. All rights reserved.