iOS - 修复cellForItemAtIndexPath图像加载问题

时间:2017-03-16 21:46:47

标签: ios objective-c uicollectionview grand-central-dispatch uicollectionviewcell

我正在构建一个包含大量图像文件的应用程序,这些文件将在集合视图中显示。由于图像的大小,我发现从URL中创建缩略图要快得多,以及使用图像缓存。当我第一次使用GCD在cellForItemAtIndexPath中实现它时,我看到了UI延迟的大幅减少,但我也注意到当集合视图进入视图并滚动时,单元格中的图像会闪烁并快速变化。我发现了一些关于类似问题的其他帖子,他们说检查单元格是否为nil应该解决问题,但不幸的是,这似乎又产生了另一个问题,其中许多图像永远不会被加载。有谁知道如何解决这个问题?

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
ObjectWithPhoto *object = self.objects[indexPath.item];
cell.imageView.image = nil;

NSString *imageName = object.imageName;
NSString *imageKey = [NSString stringWithFormat:@"%@_thumbnail", imageName];
if ([[ImageCache sharedCache] imageForKey:imageKey]) {
    cell.imageView.image = [[ImageCache sharedCache] imageForKey:imageKey];
} else {
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        NSURL *imageURL = [[NSBundle mainBundle] URLForResource:imageName withExtension:@"jpg"];
        CGSize imageSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.width);
        UIImage *thumbnail = [UIImage createThumbnailFromURL:imageURL imageSize:imageSize];
        [[ImageCache sharedCache] setImage:thumbnail forKey:imageKey];
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            PhotoCell *cellToUpdate = (id)[collectionView cellForItemAtIndexPath:indexPath];
            if (cellToUpdate) {
                cellToUpdate.imageView.image = thumbnail;
            } else {
                NSLog(@"cell is no long visible");
            }
        });
    });
}
return cell;
}

2 个答案:

答案 0 :(得分:1)

也许您对您的解决方案感到满意,但我不是。我认为你所看到的至少一个奇怪的来源是在你需要的图像没有被缓存的情况下,不清除图像(或将图像设置为占位符)。请记住,一旦开始滚动,图像就不会出现在缓存中,但重用的单元格图像将被设置 - 而且错误地设置为其他indexPath的图像。所以,修一个......

if ([[ImageCache sharedCache] imageForKey:imageKey]) {
    cell.imageView.image = [[ImageCache sharedCache] imageForKey:imageKey];
} else {
    // fix one: clear the cell's image now, if it's set, it's wrong...
    cell.imageView.image = nil; // or a placeholder
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        // ... 

其次,每当我看到某人调用他们自己的cellForItem数据源方法并将值戳到单元格中时,我会抛出一个黄色标记。这更简洁,更有礼貌......

cell.imageView.image = nil; // or a placeholder
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    NSURL *imageURL = [[NSBundle mainBundle] URLForResource:imageName withExtension:@"jpg"];
    CGSize imageSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.width);
    UIImage *thumbnail = [UIImage createThumbnailFromURL:imageURL imageSize:imageSize];
    [[ImageCache sharedCache] setImage:thumbnail forKey:imageKey];
    dispatch_async(dispatch_get_main_queue(), ^(void) {
        // fix two: don't get the cell.  we know the index path, reload it!
        [collectionView reloadItemsAtIndexPaths:@[indexPath]];
        // deleted evil stuff that was here
    });
});

答案 1 :(得分:0)

我想我找到了解决这个问题的方法。当检查单元格是否仍然可用或为零时,即使我发誓我仍然可以在屏幕上看到它,它似乎返回零。考虑到这一点,我尝试告诉集合视图重新加载数据,如果单元格返回零,它的工作原理!平滑滚动和充满无闪烁的图像。

{{1}}