如何在Swift async/await并行场景下按任务完成顺序赋值结果
实现按任务完成顺序赋值的方案
你原有代码的阻塞来源于async let搭配顺序await的写法,必须先等待第一个任务返回才会处理第二个任务的结果,要实现解耦可以通过结构化并发的任务组实现,具体方案如下:
方案1:使用DiscardingTaskGroup(推荐,iOS 16+/macOS 13+)
任务组属于结构化并发的实现,会自动管理子任务的生命周期,每个子任务完成后立即执行对应赋值逻辑,无需等待其他任务结束:
public func loadData() async { // 声明无返回值的丢弃型任务组 await withDiscardingTaskGroup(of: Void.self) { group in // 提交图片加载子任务 group.addTask { [weak self] in guard let self else { return } let img = await self.loadImage() // UI操作必须切换到主Actor执行 await MainActor.run { self.img = img } } // 提交简介加载子任务 group.addTask { [weak self] in guard let self else { return } let bio = await self.loadBio() await MainActor.run { self.bio = bio } } } }
方案优势:
- 两个加载任务完全并行,哪个先完成就立刻执行对应的赋值和UI更新,完全解耦
- 自动继承父任务的取消上下文,调用方取消
loadData任务时,两个未完成的加载任务会同步取消,不会产生内存泄漏 - 自动等待所有子任务执行完毕后才退出
loadData函数,符合异步函数的执行预期
方案2:兼容低版本实现(iOS 15+/macOS 12+)
如果需要适配更低系统版本,可以使用withThrowingTaskGroup替代,仅需忽略返回值即可:
public func loadData() async { do { try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { [weak self] in guard let self else { return } let img = await self.loadImage() await MainActor.run { self.img = img } } group.addTask { [weak self] in guard let self else { return } let bio = await self.loadBio() await MainActor.run { self.bio = bio } } // 等待所有子任务完成 try await group.waitForAll() } } catch { // 按需处理任务取消等异常 } }
注意事项
- 如果你的
UserProfile类已经被标记为@MainActor,则不需要额外加MainActor.run包裹赋值逻辑 - 若加载任务本身可能抛出错误,可以在对应的子任务内部单独添加
do/catch处理,单个任务失败不会影响另一个任务的执行 - 不要直接在
loadData内用非结构化的Task { }启动子任务,否则父任务取消时子任务不会同步关闭,容易产生孤立任务和内存泄漏
内容的提问来源于stack exchange,提问作者Aykhan Hagverdili
相关产品推荐
相关产品推荐

