Swift 6.1 `withTaskGroup` & `withThrowingTaskGroup` 新语法导读

为什么需要 TaskGroup?

在 Swift 并发里,当你想:

  • 同时发起 N 个异步任务(如批量下载图片)
  • 等全部完成再汇总结果
  • 支持中途取消、错误传播

手动 Task { } 会显得碎片化且难以管理。

withTaskGroup / withThrowingTaskGroup 提供官方"任务组"抽象:

  1. 统一并发上限(线程池复用)
  2. 自动生命周期管理,无内存泄漏
  3. 支持结构化取消与错误聚合

Swift 6.1 的新语法亮点

版本 声明方式 是否必填子任务返回类型
≤ Swift 6.0 withTaskGroup(of: Int.self) ✅ 必须显式 of: Type.self
Swift 6.1 withTaskGroup { group in ... } ❌ 编译器自动推断

→ 去掉 of: 后,代码更短、重构更安心;复杂元组/struct 类型不再写两遍。

最小可运行示例:类型推断实战

  1. 简单数据并行
swift 复制代码
func fetchNumbers() async -> [Int] {
    await withTaskGroup { group in          // ← 不再需要 of: Int.self
        for i in 1...3 {
            group.addTask {                 // 返回 Int
                return i * 2
            }
        }

        var results = [Int]()
        for await value in group {
            results.append(value)
        }
        return results.sorted()
    }
}

// 使用
Task {
    let nums = await fetchNumbers()
    print(nums)   // [2, 4, 6]
}
  1. 复杂类型同样受益
swift 复制代码
struct ImageInfo { let url: URL, size: Int, checksum: UInt32 }

func batchDownload(_ urls: [URL]) async -> [ImageInfo] {
    do  {
        let infos = try await withThrowingTaskGroup { group in          // 自动推断 ImageInfo
            for url in urls {
                group.addTask {
                    let (data, _) = try await URLSession.shared.data(from: url)
                    return ImageInfo(
                        url: url,
                        size: data.count,
                        checksum: 2
                    )
                }
            }
            
            var infos = [ImageInfo]()
            for try await info in group {
                infos.append(info)
            }
            return infos
        }
        return infos
    } catch {
        print(error.localizedDescription)
    }
    return []
}

→ 若返回类型日后增加字段,无需改动 withTaskGroup 声明。

ThrowingTaskGroup:允许子任务抛出错误

  1. 基础示例(Swift 6.1 同样省 of:
swift 复制代码
func fetchUserInfo(ids: [String]) async throws -> [User] {
    try await withThrowingTaskGroup { group in   // 推断 String & User
        for id in ids {
            group.addTask {
                return try await API.user(id: id)  // 可能抛出
            }
        }

        var users = [User]()
        for try await user in group {              // 注意 try
            users.append(user)
        }
        return users
    }
}
  1. 错误传播规则
  • 任一子任务 throw → 整个组立即 throw(默认)
  • 想收集所有成功 + 单独处理失败 → 用 group.addTaskUnlessCancelled + do catch 内部吞错
swift 复制代码
for try await user in group {
    // 这里 throw 会**中断**后续任务
}

→ 需要"全部完成再统一处理"请参考 group.next() 手动迭代。

与 Swift 6 并发隔离的兼容

TaskGroup 的 addTask 继承调用者的隔离域:

swift 复制代码
@MainActor
class VM {
    func loadImages() async {
        await withTaskGroup { group in          // 主线程创建
            for url in urls {
                group.addTask {                 // 子任务**脱离**主线程
                    let data = try await URLSession.shared.data(from: url).0
                    return UIImage(data: data)!
                }
            }
            // 汇总时可回到主线程
            for await img in group {
                self.images.append(img)
            }
        }
    }
}

→ 网络下载在全局执行器,汇总后 images 回主线程,安全。

六、常见坑 & 最佳实践

陷阱 说明 修复
忘记 for await导致永远挂起 组内任务完成但结果未被消费 务必用 for awaitwhile let value = await group.next()
捕获 self造成循环引用 addTask { self.view.reload() } 使用 [weak self]或先把数据拉出来
想"无论成败都收集" 默认 for try await一遇 throw 就中断 内部 do catch手动 resume成功/失败数组
需要限制并发数量 withTaskGroup会全开 使用 AsyncSequence+ AsyncChannel或信号量

一句话总结

"批量并发用 Group,Swift 6.1 起别再写 of:。"

记住口诀:"普通组用 withTaskGroup,会抛错就 withThrowingTaskGroup;结果靠 for await 扫,错误用 try 收。"

去掉类型标注后,代码更短、重构更安心;让编译器多干活,你少写两行!

相关推荐
Kapaseker7 小时前
Swift 构建 Android 应用?它来了
ios·swift
HarderCoder12 小时前
Swift 协议(Protocol)指南(四):协议扩展(Protocol Extension)——让“协议”自己也有默认实现
swift
HarderCoder12 小时前
Swift 协议(Protocol)指南(三):Primary Associated Type、some/any 与泛型式协议实战
swift
Digitally12 小时前
11种方法解决iPhone上共享相册不显示的问题[2025]
ios·iphone
HarderCoder13 小时前
Swift 协议(Protocol)指南(二):关联类型、Self 约束与泛型递归,一次彻底搞懂
swift
HarderCoder13 小时前
Swift 协议(Protocol)指南(一):从语法到实战
swift
HarderCoder13 小时前
Swift TaskGroup 结果顺序踩坑指南:为什么返回顺序和创建顺序不一致,以及最通用的修复办法
swift
Swift社区21 小时前
iOS 基于 Foundation Model 构建媒体流
ios·iphone·swift·媒体
库奇噜啦呼1 天前
【iOS】音频与视频播放
ios·音视频·cocoa
大熊猫侯佩1 天前
黑衣人档案:用 Apple Foundation Models + SwiftUI 打造 AI 聊天机器人全攻略
ios·swiftui·ai编程