简介
Swift Concurrency(async/await)是从 Swift 5.5 开始引入的一套并发编程模型,用来替代传统的回调(callback)、闭包嵌套(callback hell)、以及部分 GCD 使用场景,让异步代码写起来像同步代码一样清晰。
async / await
- async:标记函数是 异步函数
- await:表示 等待异步结果
本质:await 会"挂起当前任务",但不会阻塞线程
示例
swift
func fetchUser() async -> String {
return "Tom"
}
func loadData() async {
let user = await fetchUser()
print(user)
}
async throws
支持错误处理(替代 callback 的 error)
swift
enum NetworkError: Error {
case failed
}
func fetchData() async throws -> String {
throw NetworkError.failed
}
func load() async {
do {
let result = try await fetchData()
print(result)
} catch {
print("error: \(error)")
}
}
Task
Task 是并发执行的基本单位,类似 GCD 的 block,也是一个对象。
- 普通 Task
scss
Task {
let data = await fetchUser()
print(data)
}
ini
let task = Task {
...
}
- Detached Task(独立线程)
scss
Task.detached {
await doSomething()
}
区别:
Task:继承当前 Actor / 优先级 / 上下文
detached:完全独立(慎用)
async let
并发执行
场景:多个接口同时请求
swift
func loadData() async {
async let user = fetchUser()
async let posts = fetchPosts()
let result = await (user, posts)
print(result)
}
TaskGroup
任务组
场景:批量请求 / 并发处理列表
csharp
func fetchAll() async {
await withTaskGroup(of: String.self) { group in
for i in 1...3 {
group.addTask {
return "Task \(i)"
}
}
for await result in group {
print(result)
}
}
}
Actor
线程安全方案
用于解决数据竞争问题(替代锁)
swift
actor Counter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
return value
}
}
scss
let counter = Counter()
Task {
await counter.increment()
let v = await counter.getValue()
print(v)
}
Actor = 自动串行队列 + 数据隔离
对比
| 方案 | 问题 |
|---|---|
| NSLock | 易死锁 |
| DispatchQueue | 需要手动管理 |
| Actor | 天然安全 |
实战应用场景
- 网络请求
csharp
func fetchUser() async -> User { ... }
func fetchPosts() async -> [Post] { ... }
func load() async {
let user = await fetchUser()
let posts = await fetchPosts()
}
------对比旧方案
arduino
fetchUser { result in
fetchPosts { posts in
// 嵌套地狱
}
}
- 多个接口并发请求
多个请求任务并行执行,等待异步结果
csharp
func loadPage() async {
async let banner = fetchBanner()
async let list = fetchList()
async let profile = fetchProfile()
let (b, l, p) = await (banner, list, profile)
}
- 主线程更新UI
swift
func loadData() {
Task {
let data = await fetchData()
await MainActor.run {
self.label.text = data
}
}
}
或 使用@MainActor
swift
@MainActor
func updateUI() {
label.text = "Hello"
}
- 取消任务
ini
let task = Task {
let data = await fetchData()
}
task.cancel()
- 图片加载
swift
func downloadImage(url: URL) async throws -> UIImage {
let (data, _) = try await URLSession.shared.data(from: url)
return UIImage(data: data)!
}
ini
let task = Task {
let image = try await downloadImage(url: url)
cell.imageView.image = image
}
注意:需要处理 cell 复用问题(取消任务)-》 避免图片错位
csharp
override func prepareForReuse() {
task?.cancel()
}
- 顺序依赖
csharp
func process() async {
let token = await login()
let data = await fetchData(token: token)
let result = await parse(data)
}
对比
| 方案 | 特点 |
|---|---|
| GCD | 底层强,但难维护 |
| Operation | 可控但复杂 |
| async/await | 简洁 + 可读性强 |
本质: • GCD:你管理线程 • async/await:系统帮你调度
总结
Swift Concurrency 本质就是:
用"同步写法"写"异步代码",并且保证线程安全