iOS - 修复cellForItemAtIndexPath图像加载问题
问题描述:
我正在构建一个应用程序,其中包含许多要在集合视图中显示的大图像文件。由于图像的大小,我发现从它们的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;
}
答
也许你对你的解决方案感到满意,但我不是。我认为至少有一个你看到的奇怪的来源是在你不需要缓存图像的情况下不清除图像(或将其设置为占位符)。请记住,只要开始滚动,图像就不会在缓存中,但重用单元格的图像将被设置 - 错误地设置为其他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
});
});
答
我想我想出了一个解决方案。在检查单元格是否仍然可用或零时,即使我发誓我仍然可以在屏幕上看到它,它似乎仍然会返回零。考虑到这一点,我试图告诉集合视图重新加载数据,如果单元格返回零,它的工作原理!平滑滚动并充满不闪烁的图像。
PhotoCell *cellToUpdate = (id)[self.collectionView cellForItemAtIndexPath:indexPath];
if (cellToUpdate) {
cellToUpdate.imageView.image = thumbnail;
} else {
NSLog(@"cell is no long visible");
[self.collectionView reloadData];
}
如果你看我的原始代码,你会注意到,我确实将图像设置为零首先。你的解决方案的其余部分是伟大的,谢谢! – Grambo