滚动浏览数千张图片时,PHImageManager的requestImage会锁定UI

时间:2018-08-16 11:49:29

标签: ios swift multithreading uikit photosframework

我有一个收藏夹视图,其中显示了所有用户的照片。基本的东西,一个获取PHAsset并在requestImage上使用PHCachingImageManager来加载缩略图的数据源。

但是最近我收到了一个错误报告,当您拥有超过5000张图像并快速滚动时,UI会冻结。经过调查,我能够重现此问题,似乎主线程在调用requestImage之后就被锁定(_lock_wait),而该调用创建的其他几十个线程(其他单元格的缩略图)正在被锁定。还锁定等待谁知道。

我尝试了几件事,但没有任何效果:

  1. 实现了UICollectionViewDataSourcePrefetching,并使用PHCachingImageManagerprefetchItemsAt事件上启动了CachingImages。有趣的是,它试图一次加载更多图像,这使情况变得更糟。而cancelPrefetchingForItemsAt(原本应该在单元格不在屏幕上时会被调用)从未被调用。

  2. 试图在速度较慢的请求上致电cancelImageRequest,在这里也没有成功。

现在我不知道该怎么办,我可以在后台dispatch_queue上运行requestImage,这样它就不会锁定我的主线程,但是由于该方法将自己生成另一个线程,因此感觉很奇怪< / p>

我的代码是这样的:

let requestOptions = PHImageRequestOptions()
requestOptions.resizeMode = .fast
requestOptions.deliveryMode = .opportunistic
requestOptions.isSynchronous = false
requestOptions.isNetworkAccessAllowed = true
return requestOptions

myManager.requestImage(for: asset, targetSize: CGSize(width: 375, height: 375), contentMode: .aspectFill, options: options) { /* use image */ }

ps:我不确定,但是这似乎仅在iOS 11上发生,现在我只能在iPhone X上进行复制

1 个答案:

答案 0 :(得分:0)

原来是问题所在:GCD dispatch concurrent queue freeze with 'Dispatch Thread Soft Limit Reached: 64' in crash log

requestImage继续创建新线程,直到达到派发线程限制并且UI冻结此_lock_wait

解决方案是设置requestOptions.isSynchronous = true,创建并发性受限的OperationQueue并将图像获取作为作业添加到该队列中。

//somewhere like viewDidLoad
operationQueue.maxConcurrentOperationCount = 54

//when setting up the cells
operationQueue.addOperation { [weak self] in
      self?.cachingImageManager.requestImage(/* params...*/) { (image) in
            OperationQueue.main.addOperation {
               //use image
            }
      }
}