iOS14下PHPickerViewController如何加载全部PHPickerResult获取选中图片数组
多选图片实现最佳实践
现有代码存在的问题
- 异步回调执行顺序不固定,直接
append会导致最终数组的顺序和用户选择顺序不一致 - 完成条件判断错误:
totalConversionsCompleted == index的逻辑完全不成立,最终需要匹配的是results.count而不是当前遍历的下标 - 线程不安全:
loadObject的回调默认在后台队列执行,多线程同时操作数组会出现数据竞争、计数错乱的问题
正确实现方案
采用DispatchGroup统一管理所有异步加载任务,预先创建固定长度的数组保证顺序,所有数组和计数操作都放在同一个串行队列(比如主队列)执行避免线程安全问题,这是官方推荐的标准实现方式。
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true) guard !results.isEmpty else { return } // 预先创建对应长度的数组,保证和用户选择顺序一致 var images: [UIImage?] = Array(repeating: nil, count: results.count) let dispatchGroup = DispatchGroup() for (index, result) in results.enumerated() { guard result.itemProvider.canLoadObject(ofClass: UIImage.self) else { continue } dispatchGroup.enter() result.itemProvider.loadObject(ofClass: UIImage.self) { object, error in defer { dispatchGroup.leave() } let image = object as? UIImage // 所有数据操作切到主队列,保证线程安全 DispatchQueue.main.async { images[index] = image } } } // 所有图片加载完成后统一回调 dispatchGroup.notify(queue: .main) { // 可根据业务需求过滤掉加载失败的nil值 let validImages = images.compactMap { $0 } // 此处处理拿到的图片数组即可 } }
可选优化点
- 如果选中的图片数量多、体积大,建议增加加载状态提示,避免用户误以为界面卡住
- 如果不需要保留加载失败的占位,可直接把成功加载的图片存入数组,无需提前占位
- 如果存在大量图片加载需求,可以限制并行加载的数量,避免内存暴涨
内容的提问来源于stack exchange,提问作者Hardip Gajera
相关产品推荐
相关产品推荐

