UICollectionViewController保持自己从异步图像加载重新排列

时间:2014-07-01 05:51:20

标签: asynchronous uicollectionview uicollectionviewcell

在我的申请中。我在主线程上得到了一堆图像URL,如下所示:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self populateCollection];
}

- (void)populateCollection
{
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:[MTGJSONBridge JSONURLWithSetCode:@"LEA"]]
                                                         options:kNilOptions
                                                           error:nil];
    NSLog(@"Json: %@", json);
    NSArray *cards = json[@"cards"];
    _URLs = [NSMutableArray arrayWithCapacity:cards.count];
    for (NSDictionary *card in cards)
    {
        NSURL *imageURL = [MTGJSONBridge URLWithSetCode:@"LEA" cardName:card[@"imageName"]];
        if (imageURL)
            [_URLs addObject:imageURL];
    }
}

这让我在0.2秒内获得了大约300个网址。然后我尝试异步加载每个URL的图像:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"reuseIdentifier";
    MTGCardCollectionCell *cell = (MTGCardCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    NSURL *url = _URLs[indexPath.row];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // No explicit autorelease pool needed here.
        // The code runs in background, not strangling
        // the main run loop.
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
        dispatch_sync(dispatch_get_main_queue(), ^{
            // This will be called on the main thread, so that
            // you can update the UI, for example.
            cell.imageView.image = image;
        });
    });
    return cell;
}

我也有:

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return _URLs.count;
}

集合加载非常快,也是异步加载(我可以在加载内容时滚动,并且会看到弹出的新图像)。问题是当我向上和向下滚动时,即使在所有图像都已加载之后,事物仍然以随机顺序重新排列:我将查看一个单元格,然后它将其图像与另一个单元格切换为没有明显的理由。为什么会这样?

1 个答案:

答案 0 :(得分:0)

我发现了一个非常简单的解决方案:

if (cell.imageView.image == nil)
{
    NSURL *url = _URLs[indexPath.row];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // No explicit autorelease pool needed here.
        // The code runs in background, not strangling
        // the main run loop.
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
        dispatch_sync(dispatch_get_main_queue(), ^{
            // This will be called on the main thread, so that
            // you can update the UI, for example.
            cell.imageView.image = image;
        });
    });
}
else
{
    NSLog(@"Cell image isn't nil");
}

我所要做的就是检查单元格是否已经加载。事实证明,只要单元格进入视图,就会调用- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath方法。即使只是在视野中。