2016-09-16 103 views
0

我正在开发一个带有示例UICollectionView的应用程序,该应用程序应该加载它从互联网上下载的一堆图标。所以基本上服务器会检索一个包含JSON文件中每个图标的URL的列表,然后应用程序解析它,然后每个单元格下载相应的图像。UICollectionView单元格图像错误

这种方法的问题似乎是,如果用户在图像下载时开始滚动,用户将开始以错误的顺序看到图像!这就像UICollectionView试图“帮助我”一样,它会呈现出错的地方!

我见过很多关于这方面的线索,我尝试了大部分建议,但迄今为止运气很好。有人看到这样的事情?

enter image description here

这是cellForItemAtIndexPath的样子:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 
PeqImage *image = [self.responseIcons objectAtIndex:indexPath.row]; 

PeqCustomCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"PeqCustomCell" forIndexPath:indexPath]; 

cell.peqImage = image; 
cell.imageName = [NSString stringWithFormat:@"%@.png",image.assetId]; 

NSString *theImageUrl = [NSString stringWithFormat:@"http://www.XXXX.com/pb/images/uncompressed/%ld.png",(long)indexPath.row]; 
[cell downloadImage:[NSURL URLWithString:theImageUrl]]; 

return cell; 

}

这是下载算法的样子(使用的UIImageView + AFNetworking):

- (void) downloadImageWithUrl:(NSURL*) url completion:(PeqCustomCellCompletionBlock)completionBlock 
{UIImage *placeholder = [UIImage imageNamed:@"placeholder"]; 
NSURLRequest *jpegURLRequest = [NSURLRequest requestWithURL:url]; 

self.imageUrl = url.absoluteString;  
[self.imageView setImageWithURLRequest:jpegURLRequest 
        placeholderImage:placeholder 
        success:^(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image) { 
        image = [self normalizeImage:image]; 
        completionBlock(image); 
        } 

        failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 

         NSLog(@"Error downloading image from network"); 
        }]; 

}

回答

1

您应该使用SDWebImage library来处理这种东西有点像,

#import <SDWebImage/UIImageView+WebCache.h> 

    .. 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
static NSString *MyIdentifier = @"MyIdentifier"; 

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; 
if (cell == nil) { 
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
            reuseIdentifier:MyIdentifier] autorelease]; 
} 

// Here we use the new provided sd_setImageWithURL: method to load the web image 
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] 
        placeholderImage:[UIImage imageNamed:@"placeholder.png"]]; 

cell.textLabel.text = @"My Text"; 
return cell; 
} 

这里的tableview的例子中,你可以使用相同的为您collection view

此库缓存图像的可重用性。

如果你想实现或知道这个东西native way的话可以参考Loading Images in UICollectionViewCell: Naive to the Clever.

+0

谢谢你的回答。我做了诡计!我正在使用另一个库 (UIImageView + AFNetworking),但尽管SDWebImage似乎比较慢,但它的工作方式与我期望的那样可以下载图像! –

0

问题在于,每当单元格被隐藏并再次显示时,您都会重新下载图像。更好的方法是预先下载所有数据,然后使用它填充collectionView。

+0

不,不要提前加载每个图像。每次按需加载并缓存它们。如果收集视图有数百个项目,但用户从不向下滚动以显示大部分项目,该怎么办?为什么要在这种情况下下载它们? – rmaddy

1

我怀疑线程是罪魁祸首。所有的UI代码都必须从主线程调用。现在使用这么多块的时候,很容易从后台线程中意外调用UI调用。当你这样做时,所有的古怪方式都会开始实现。

我想尝试改变你的代码最后一段,以便在主线程上调用图像调用。我刚刚添加了一个dispatch_async()函数。

self.imageUrl = url.absoluteString; 
[self.imageView setImageWithURLRequest:jpegURLRequest 
         placeholderImage:placeholder 
           success:^(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image){ 
            dispatch_async(dispatch_get_main_queue(), ^{ 
            image = [self normalizeImage:image]; 
            completionBlock(image); 
            }); 
           } 
           failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 
            NSLog(@"Error downloading image from network"); 
           }]; 
1

的问题是,集合视图细胞被重用。因此,您要告诉单元格在屏幕上下载特定图像,然后在收集视图需要另一个单元格时重新使用,然后您告诉同一单元格下载另一个图像。最后下载哪个图像是最后一个将要显示的图像。

在您的下载完成块中,在设置image = [self normalizeImage:image];之前,您应该检查请求url是否与当前的self.imageUrl匹配。如果没有,则该图像来自旧请求,并且您不希望将其显示在单元格中。