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

Posted

技术标签:

【中文标题】滚动浏览数千张图片时,PHImageManager 的 requestImage 会锁定 UI【英文标题】:PHImageManager's requestImage locks UI when scrolling through thousands of images 【发布时间】:2018-08-16 11:49:28 【问题描述】:

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

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

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

    实现了UICollectionViewDataSourcePrefetching,并使用PHCachingImageManagerprefetchItemsAt 事件上启动CachingImages。有趣的是,它使事情变得更糟,因为它试图一次加载更多图像。而cancelPrefetchingForItemsAt,应该在单元格离开屏幕时被调用,但从未被调用。

    尝试在较慢的请求上调用cancelImageRequest,在这里也没有成功。

现在我不知道还能做什么,我可以在后台 dispatch_queue 上运行 requestImage,这样它就不会锁定我的主线程,但感觉很奇怪,因为该方法会自行生成另一个线程

我的代码是这样的:

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 上重现

【问题讨论】:

你检查同步模式是否为真 我现在正在测试它,效果更好,但是我失去了在高质量图像完成之前加载更快、质量更低的图像的选项...... 哦,我还是得到了锁,但现在在应用程序的后期,当我设置当前的 opengl 上下文时。这真的很奇怪。 似乎在重用单元格时 cancelImageRequest 完成了这项工作!但我仍然需要与客户确认。如果可行,我会更新答案 【参考方案1】:

原来这是问题所在: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
            
      

【讨论】:

在这种情况下,如何在快速滚动时获得质量较低的图像?另外,您如何管理请求取消?

以上是关于滚动浏览数千张图片时,PHImageManager 的 requestImage 会锁定 UI的主要内容,如果未能解决你的问题,请参考以下文章

CSS浏览器下边出现滚动条 急!!

滚动 RecyclerView 时出现“打开的文件太多”

PHImageManager 在许多图像请求后崩溃

Swiper滚动图片显示当前图片是第几张图片

UIScrollView 滚动时延迟

图片滚动(待美化)