Swift中PHAsset数组转URL数组:如何等待异步任务完成后返回结果
解决PHAsset数组转URL数组的异步等待问题
核心问题在于PHAsset的URL获取是异步操作(比如调用requestContentEditingInput或requestAVAsset这类方法),如果直接在循环里执行这些异步逻辑,函数会在所有异步任务完成前就返回空数组,这就是你不确定结果是否始终正确的原因。下面提供两种可靠的实现方式,确保所有URL获取完成后再返回结果:
方案1:使用Async/Await(iOS 15+,推荐)
从iOS15开始,Photos框架原生支持异步/等待API,代码更简洁且不会阻塞主线程。你可以把getUrlsFromPHAssets改成异步函数:
import Photos func getUrlsFromPHAssets(_ assets: [PHAsset]) async throws -> [URL] { var urls = [URL]() for asset in assets { // 异步等待每个Asset的编辑输入 let input = try await asset.requestContentEditingInput(with: nil) // 根据Asset类型取对应的URL if let url = input.fullSizeImageURL ?? input.fullSizeVideoURL { urls.append(url) } } return urls }
主线程调用方式:
因为是异步函数,你需要用await等待结果,记得包裹在Task中避免阻塞主线程:
Task { do { let targetAssets: [PHAsset] = // 你的PHAsset数组 let fetchedUrls = try await getUrlsFromPHAssets(targetAssets) // 这里处理获取完成的URL数组 print("所有URL已获取:\(fetchedUrls)") } catch { print("URL获取失败:\(error.localizedDescription)") } }
方案2:使用DispatchGroup(兼容iOS <15)
如果需要支持iOS15以下版本,可以用DispatchGroup跟踪所有异步任务的完成状态。注意绝对不要在主线程直接调用group.wait(),否则会阻塞UI,建议结合后台线程使用:
import Photos func getUrlsFromPHAssets(_ assets: [PHAsset], completion: @escaping ([URL]) -> Void) { var urls = [URL]() let group = DispatchGroup() for asset in assets { group.enter() asset.requestContentEditingInput(with: nil) { input, _ in defer { group.leave() } // 确保任务结束后标记完成 guard let input = input else { return } if let url = input.fullSizeImageURL ?? input.fullSizeVideoURL { urls.append(url) } } } // 所有任务完成后回调结果 group.notify(queue: .main) { completion(urls) } }
主线程调用方式:
let targetAssets: [PHAsset] = // 你的PHAsset数组 getUrlsFromPHAssets(targetAssets) { fetchedUrls in // 这里处理获取完成的URL数组 print("所有URL已获取:\(fetchedUrls)") }
为什么你的当前结果看似正常?
大概率是测试时的PHAsset数量少、设备性能较好,异步任务刚好在函数返回前侥幸完成了。但这种情况是不可靠的——当资产数量多、设备负载高时,异步任务还没执行完函数就返回了,结果必然会缺失URL。上面的两种方案都能确保所有异步任务完成后再返回/回调结果,不会出现随机错误。
内容的提问来源于stack exchange,提问作者Khoa
相关产品推荐
相关产品推荐

