异步加载图像,单元格中的图像错误

时间:2015-07-14 23:49:59

标签: ios objective-c asynchronous uicollectionview

我有UICollectionView我正在加载多个图片。从我读过的内容来看,为了将正确的图像与每个单元格匹配,我需要将UIImageView子类化并在那里获取图像。因为每次我collectionView reloadData,一些图像都会重复,并且它们都会出现故障。但我不确定如何做到这一点,并没有找到任何教程。我正在使用Parse作为数据库。

 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
albumImageCell *cell = (albumImageCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

     if (cell == nil) {
         cell = [[albumImageCell alloc]init];
     }

     PFObject *temp = [_dataArray objectAtIndex:indexPath.row];
     PFFile *file = [temp objectForKey:@"imageThumbnail"];

     if (![cell.hasImage isEqualToString:@"YES"]) {
         dispatch_async(imageQueue, ^{
             NSData *data = [file getData];
                 if (data) {
                     UIImage *image = [UIImage imageWithData:data];

                     dispatch_async(dispatch_get_main_queue(), ^(void){
                         cell.imageView.image = image;
                         cell.hasImage = @"YES";
                     });

                 }
         });
     }

     return cell;
}

3 个答案:

答案 0 :(得分:5)

解决此问题的一种方法是,一旦您重新回到主队列,就会再次查询单元格的集合视图。这段代码应该有效:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
albumImageCell *cell = (albumImageCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

     if (cell == nil) {
         cell = [[albumImageCell alloc]init];
     }

     PFObject *temp = [_dataArray objectAtIndex:indexPath.row];
     PFFile *file = [temp objectForKey:@"imageThumbnail"];

     if (![cell.hasImage isEqualToString:@"YES"]) {
         dispatch_async(imageQueue, ^{
             NSData *data = [file getData];
                 if (data) {
                     UIImage *image = [UIImage imageWithData:data];

                     dispatch_async(dispatch_get_main_queue(), ^(void){
                         // cellAgain will be the actual cell at that index path, if it is visible. 
                         // If it is not visible, cellAgain will be nil.
                         albumImageCell *cellAgain = [collectionView cellForItemAtIndexPath:indexPath];
                         cellAgain.imageView.image = image;
                         cellAgain.hasImage = @"YES";
                     });

                 }
         });
     }

     return cell;
}

答案 1 :(得分:0)

我做了一个小教程'回答this question。虽然问题涉及核心数据,但我的答案适用于任何数据源,因此您应该能够适应您的用例。

当你回到主队列时,你要注意的一件事是内部块。鉴于您不知道到达该点需要多长时间,该单元格可能不再与该图像相关(可能已被重用),因此您需要进行一些额外的检查......

(a)是否还需要图片?

if ([[tableView indexPathsForVisibleRows] containsObject:indexPath])

(b) 单元格是图像的正确单元格吗?

 UITableViewCell * correctCell = [self.tableView cellForRowAtIndexPath:indexPath];

虽然本教程仍然有效,但我现在倾向于进一步抽象。由于viewController必须处理UIKit和Core Data等线程不安全的实体,因此最好在主线程上保留所有 viewController代码。背景队列抽象应该在较低级别进行,优选地在模型代码中进行。

答案 2 :(得分:0)

我最终做的是继承UIImaveView,然后将图像文件传递到cellForRow

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
albumImageCell *cell = (albumImageCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    if (cell == nil) {
        cell = [[albumImageCell alloc]init];
    }

    PFObject *temp = [_dataArray objectAtIndex:indexPath.row];
    PFFile *file = [temp objectForKey:@"imageThumbnail"];

    [cell.imageView setFile:file];

    return cell;
}  

然后在customImageView -

- (void) setFile:(PFFile *)file {

    NSString *requestURL = file.url; // Save copy of url locally (will not change in block)
    [self setUrl:file.url]; // Save copy of url on the instance
    self.image = nil;
    [file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
        if (!error) {
            UIImage *image = [UIImage imageWithData:data];
            if ([requestURL isEqualToString:self.url]) {
                [self setImage:image];
                [self setNeedsDisplay];
            }
        } else {
            NSLog(@"Error on fetching file");
        }
    }];
}  

但每次用户滚动到新单元格时,这都会获取数据。因此我仍然试图找出如何将特定图像与单元格匹配,而不是每次都获取数据。

相关问题