使用 dispatch_async 在 UICollectionView 中加载图片
Posted
技术标签:
【中文标题】使用 dispatch_async 在 UICollectionView 中加载图片【英文标题】:Using dispatch_async to load images in UICollectionView 【发布时间】:2015-07-13 23:48:13 【问题描述】:我正在使用 Parse 来存储图像。我正在尝试异步加载图像,这样它就不会干扰collectionView
滚动。我是使用dispatch_async
的新手,不太确定如何正确实施它。我也研究过延迟加载,但我认为这会起作用。但事实并非如此,collectionView
滚动条很不稳定。谢谢
- (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:@"image"];
if (cell.hasImage == FALSE)
dispatch_async(imageQueue, ^
NSData *data = [file getData];
if (data)
dispatch_async(dispatch_get_main_queue(), ^(void)
cell.imageView.image = [UIImage imageWithData:data];
cell.hasImage = TRUE;
);
);
return cell;
【问题讨论】:
这段代码存在的问题超出了波动性。在后台加载图像时,可以重复使用单元格。您可能会得到连接到特定单元格的错误图像。我认为我见过的最好的解决方案是创建一个异步 UIImageView 类,该类在后台自行加载。我不知道这个特定的是否好,但您可以尝试一下:github.com/nicklockwood/AsyncImageView @EricS 是的,这曾经发生过。你认为我可以在我的自定义collectionViewCell
文件而不是子类UIImageView
中加载和设置图像吗?
当然,但是您必须通过实现prepareForReuse
方法来处理单元格被重用的情况。你会想要取消现有的网络请求,或者至少忽略结果,然后创建一个新请求。请记住,第二个请求可能会在第一个请求之前返回 - 无法保证它们会以任何特定顺序返回。
【参考方案1】:
因为UIImage +imageWithData
方法有点阻塞主线程。
dispatch_async(dispatch_get_main_queue(), ^(void)
cell.imageView.image = [UIImage imageWithData:data];
所以这些行应该如下所示。
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^(void)
cell.imageView.image = image;
此外,在 UIImage 对象实际显示或渲染之前,UIImage 不会立即解码图像。见https://***.com/a/19251240/629118。因此,以下代码是摆脱不连贯滚动的最佳方法之一。
UIImage *image = [UIImage imageWithData:data];
UIGraphicsBeginImageContext(CGSizeMake(1,1));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), [image CGImage]);
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^(void)
cell.imageView.image = image;
【讨论】:
我们对这个问题的解决方案是在后台线程而不是 UIImage 上创建一个 CGImageRef 并将 CGImageRef 传递给主线程。主线程将从 CGImageRef 创建一个 UIImage,这非常快。 (UIImage 在早期版本的 ios 中也不是线程安全的,所以我们养成了从不在辅助线程上使用它们的习惯)以上是关于使用 dispatch_async 在 UICollectionView 中加载图片的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 dispatch_async() 方法时 AsyncSocket 无法连接到主机?
为啥在 requestAccessToEntity:completion 中使用 performSegueWithIdentifier 时使用 dispatch_async?
dispatch_async 与 NSOperation 队列