AFNetworking 和集合视图阻塞主线程

Posted

技术标签:

【中文标题】AFNetworking 和集合视图阻塞主线程【英文标题】:AFNetworking and Collection View Blocking Main Thread 【发布时间】:2016-03-13 21:52:32 【问题描述】:

在使用 AFNetworking 和集合视图时遇到了一点问题。我正在使用 AFNetworking 调用 Foursquare 的照片 API。我构建了 Foursquare 提供给我的照片 URL,并将该 URL 存储在 realm.io 中。然后我从领域调用foursquare URL,并在我的集合视图cellForItemAtIndexPath 中的AFNetworking 的setImageWithURL 方法上使用这些URL。当最初加载完成的视图控制器时,它似乎暂时阻塞了主线程(大约 1 秒),直到图像开始显示在我的集合视图上。我不知道为什么,想知道是否有人对更好的性能有建议?提前致谢!

下面是我的cellForItemAtIndexPath 代码:

 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
static NSString *identifier = @"photoCell";

UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *wineryImageView = (UIImageView *)[cell viewWithTag:100];

_photo = [_wineryPhotosArray objectAtIndex:indexPath.row];

[wineryImageView setImageWithURL:[NSURL URLWithString:_photo.photoURLString] placeholderImage:[UIImage imageNamed:@"Grapes"]];

return cell;
 

_wineryPhotosArray 是我的领域数组,其中包含来自 Foursquare 的照片 URL。另外,我尝试将setImageWithURL 方法包装在dispatch_async(dispatch_get_main_que) 中,但这似乎没有多大作用。

这是我的 Foursquare Photo API 调用代码,然后将 URL 存储在领域中:

 -(void)getFoursquarePhotos 

FoursquarePhotosAPI *foursquarePhotoAPI = [FoursquarePhotosAPI initWithClientSecret:_clientSecret clientID:_clientId venueId:_venueId];

[foursquarePhotoAPI foursquarePhotosAPI:^(NSDictionary *data) 

    for (NSDictionary *foursquarePhotos in data) 

        _photo = [Photo initWithPrefix:[foursquarePhotos valueForKey:@"prefix"] size:[NSString stringWithFormat:@"%@x%@", [foursquarePhotos valueForKey:@"height"], [foursquarePhotos valueForKey:@"width"]] suffix:[foursquarePhotos valueForKey:@"suffix"]wineryId:_venueId];

        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm beginWriteTransaction];
        [realm addOrUpdateObject:_photo];
        [realm commitWriteTransaction];
        [self.collectionView reloadData];
    
  ];  

【问题讨论】:

您可以使用 stackshot 查看冻结时发生的情况,并使用时间分析器(在 Instruments 中)找出为什么需要这么长时间。 您也可以尝试将beginWriteTransactioncommitWriteTransactionreloadData 移到for 循环之外,这样您就不会提交很多事务,并且您只需重新加载一次数据,当完成。您也可以尝试在后台线程上执行领域操作,然后在完成后在主线程上重新加载集合视图。 感谢将领域写入和重新加载数据移到 for 循环之外似乎有所帮助。我认为这就是暂时放慢速度的原因。 【参考方案1】:

Aaron 绝对正确,将 beginWriteTransactioncommitWriteTransaction 拉出 for 循环应该可以提高性能。 Realm 的一般经验法则是在一个写入事务中尝试并批处理尽可能多的写入操作。

除此之外,我觉得您无法接受的滚动性能的原因是您正在下载的图像数据在您将它们添加到各自的图像视图后在主线程上被解码。

图像在调用 [UIImageView setImage:] 时不会被解码,但会在 GPU 即将渲染视图时由 Core Animation 延迟加载(因此将该代码封装在 dispatch_async 中不会”什么都不做)。

根据this Stack Overflow answer,AFNetworking 的UIImage 下载类别非常简单,本身不执行此背景图像解码,但它提出了几种解决方案,例如AFImageRequestOperationSDWebImage .

有关 ios 图像解码/渲染管道的更多信息,我建议您观看 WWDC 2014 视频:iOS 应用程序的高级图形和动画。 :)

【讨论】:

感谢@TiM 提供的额外信息。我将观看 WWDC 视频。对这一切还有点新意,但希望这能让我有更深入的了解。

以上是关于AFNetworking 和集合视图阻塞主线程的主要内容,如果未能解决你的问题,请参考以下文章

查找阻塞主线程的代码的最佳方法是啥?

在不阻塞主线程的情况下更新 tableView

AFNetworking 可以轻松返回 UIImage,但我如何返回 NSData?

信号量等待导致 AFNetworking 阻塞?

生成新单元格时清除集合视图单元格(iOS7 - AFNetworking)

子线程怎么不阻塞主线程