aka*_*aru 10 multithreading objective-c nsoperation ios6 uicollectionview
我有UICollectionView,但同样的方法应该适用UITableViews.我的每个单元格都包含一个从磁盘加载的图像,这是一个很慢的操作.为了缓解这种情况,我使用异步调度队列.这样可以正常工作,但是快速滚动导致这些操作堆叠起来,这样单元格将按顺序将其图像从一个更改为另一个,直到最后一次调用停止.
在过去,我已经检查了细胞是否仍然可见,如果不是,我不会继续.但是,这不适用于UICollectionView,无论如何它效率不高.我正在考虑迁移使用NSOperations,可以取消,以便只修改单元格的最后一次调用将通过.我可以通过检查操作是否已在prepareForReuse方法中完成来实现此操作,如果没有则取消它.我希望有人在过去处理过这个问题,并且可以提供一些提示或解决方案.
rob*_*off 21
会话211 - 在WWDC 2012上构建iOS上的并发用户界面,讨论了当后台任务赶上时(从38m15开始)单元格图像更改的问题.
这是你如何解决这个问题.将图像加载到后台队列后,使用索引路径查找显示包含该图像的项目的当前单元格(如果有).如果您有一个单元格,请设置单元格的图像.如果你得到nil,那么当前没有单元格显示该项目,所以只丢弃图像.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    cell.imageView.image = nil;
    dispatch_async(myQueue, ^{
        [self bg_loadImageForRowAtIndexPath:indexPath];
    });
    return cell;
}
- (void)bg_loadImageForRowAtIndexPath:(NSIndexPath *)indexPath {
    // I assume you have a method that returns the path of the image file.  That
    // method must be safe to run on the background queue.
    NSString *path = [self bg_pathOfImageForItemAtIndexPath:indexPath];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    // Make sure the image actually loads its data now.
    [image CGImage];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self setImage:image forItemAtIndexPath:indexPath];
    });
}
- (void)setImage:(UIImage *)image forItemAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = (MyCell *)[collectionView cellForItemAtIndexPath:indexPath];
    // If cell is nil, the following line has no effect.
    cell.imageView.image = image;
}
这是一种简单的方法,可以减少加载视图不再需要的图像的后台任务的"堆叠".给自己一个NSMutableSet实例变量:
@implementation MyViewController {
    dispatch_queue_t myQueue;
    NSMutableSet *indexPathsNeedingImages;
}
当您需要加载图像时,将单元格的索引路径放在集合中,并调度一个任务,该任务将一个索引路径从集合中移出并加载其图像:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    cell.imageView.image  = nil;
    [self addIndexPathToImageLoadingQueue:indexPath];
    return cell;
}
- (void)addIndexPathToImageLoadingQueue:(NSIndexPath *)indexPath {
    if (!indexPathsNeedingImages) {
        indexPathsNeedingImages = [NSMutableSet set];
    }
    [indexPathsNeedingImages addObject:indexPath];
    dispatch_async(myQueue, ^{ [self bg_loadOneImage]; });
}
如果单元格停止显示,请从集合中删除单元格的索引路径:
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    [indexPathsNeedingImages removeObject:indexPath];
}
要加载图像,请从集合中获取索引路径.我们必须为此调度回主队列,以避免集合上的竞争条件:
- (void)bg_loadOneImage {
    __block NSIndexPath *indexPath;
    dispatch_sync(dispatch_get_main_queue(), ^{
        indexPath = [indexPathsNeedingImages anyObject];
        if (indexPath) {
            [indexPathsNeedingImages removeObject:indexPath];
        }
    }
    if (indexPath) {
        [self bg_loadImageForRowAtIndexPath:indexPath];
    }
}
该bg_loadImageForRowAtIndexPath:方法与上述相同.但是当我们实际在单元格中设置图像时,我们还想从集合中删除单元格的索引路径:
- (void)setImage:(UIImage *)image forItemAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = (MyCell *)[collectionView cellForItemAtIndexPath:indexPath];
    // If cell is nil, the following line has no effect.
    cell.imageView.image = image;
    [indexPathsNeedingImages removeObject:indexPath];
}
您是否尝试过使用SDWebImage开源框架,该框架可以从Web下载图像并以异步方式缓存它们?它的工作非常好,UITableViews应该和它一样好UICollectionViews.你只需使用扩展的setImage:withURL:方法,UIImageView它就会产生魔力.
| 归档时间: | 
 | 
| 查看次数: | 7880 次 | 
| 最近记录: |