0

我正在構建一個應用程序,其中包含許多要在集合視圖中顯示的大圖像文件。由於圖像的大小,我發現從它們的URL創建縮略圖要快得多,並且使用圖像緩存。當我第一次在使用GCD的cellForItemAtIndexPath中實現這個功能時,我發現UI滯後減少很多,但我也注意到當收集視圖進入視圖並滾動時,單元格中的圖像會閃爍並迅速改變。我發現了一些關於類似問題的其他帖子,他們說,檢查單元格是否先是零應該解決問題,但不幸的是,這似乎造成另一個問題,其中許多圖像從未加載過。有誰知道如何解決這一問題?iOS - 修復cellForItemAtIndexPath圖像加載問題

- (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; 
} 

回答

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 
    }); 
}); 
+0

如果你看我的原始代碼,你會注意到,我確實將圖像設置爲零首先。你的解決方案的其餘部分是偉大的,謝謝! – Grambo

0

我想我想出了一個解決方案。在檢查單元格是否仍然可用或零時,即使我發誓我仍然可以在屏幕上看到它,它似乎仍然會返回零。考慮到這一點,我試圖告訴集合視圖重新加載數據,如果單元格返回零,它的工作原理!平滑滾動並充滿不閃爍的圖像。

PhotoCell *cellToUpdate = (id)[self.collectionView cellForItemAtIndexPath:indexPath]; 
if (cellToUpdate) { 
    cellToUpdate.imageView.image = thumbnail; 
} else { 
    NSLog(@"cell is no long visible"); 
    [self.collectionView reloadData]; 
}