滚动浏览数千张图片时,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
,并使用PHCachingImageManager
在prefetchItemsAt
事件上启动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的主要内容,如果未能解决你的问题,请参考以下文章