大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
并发与 async/await
Swift 并发模型:async/await、Task、Actor 保证线程安全。对照 /roadmaps/swift-ui「并发」节点,网络加载与 UI 更新必须正确分离主线程与后台任务。
学习目标
- 理解
@MainActor与主线程 UI 更新规则 - 用
Task、TaskGroup执行异步工作 - 掌握 Actor 隔离可变状态
- 在 SwiftUI 中用
.task与 async ViewModel 加载数据
核心概念
async/await 与 MainActor
struct Weather: Decodable {
let city: String
let temp: Double
let condition: String
}
enum WeatherError: Error {
case networkFailed
}
func fetchWeather(city: String) async throws -> Weather {
try await Task.sleep(nanoseconds: 500_000_000)
return Weather(city: city, temp: 22.5, condition: "晴")
}
@MainActor
final class WeatherViewModel: ObservableObject {
@Published var weather: Weather?
@Published var isLoading = false
@Published var errorMessage: String?
func load(city: String) async {
isLoading = true
errorMessage = nil
do {
weather = try await fetchWeather(city: city)
} catch {
errorMessage = "加载失败"
}
isLoading = false
}
}
struct WeatherView: View {
@StateObject private var viewModel = WeatherViewModel()
@State private var city = "北京"
var body: some View {
VStack(spacing: 16) {
TextField("城市", text: $city)
.textFieldStyle(.roundedBorder)
if viewModel.isLoading {
ProgressView("加载中…")
} else if let w = viewModel.weather {
Text("\(w.city) \(w.temp, specifier: "%.1f")°C")
Text(w.condition).foregroundStyle(.secondary)
}
Button("刷新") {
Task { await viewModel.load(city: city) }
}
}
.padding()
.task(id: city) { await viewModel.load(city: city) }
}
}
@MainActor 保证 @Published 变更在主线程;ViewModel 标注 @MainActor 是 SwiftUI 最佳实践。
Actor 与 TaskGroup
actor ImageCache {
private var storage: [URL: Data] = [:]
func data(for url: URL) -> Data? {
storage[url]
}
func store(_ data: Data, for url: URL) {
storage[url] = data
}
}
func fetchMultiple(urls: [URL]) async -> [Data] {
await withTaskGroup(of: Data?.self) { group in
for url in urls {
group.addTask {
try? Data(contentsOf: url)
}
}
var results: [Data] = []
for await data in group {
if let data { results.append(data) }
}
return results
}
}
Actor 串行化内部可变状态,避免数据竞争;TaskGroup 并行执行子任务并收集结果。
与 React/SwiftUI 对照
| Swift 并发 | React | SwiftUI |
|---|---|---|
async/await | async/await | ViewModel 方法 |
@MainActor | —(单线程 DOM) | UI 状态更新 |
Task { } | useEffect 内 IIFE | 按钮触发 |
.task | useEffect + cleanup | 视图生命周期 |
Actor | Web Worker(近似) | 线程安全缓存 |
TaskGroup | Promise.all | 并行请求 |
React 18 的 useTransition 降低 UI 阻塞;Swift 用 Main Actor 隔离 UI,后台 Task 完成后 @MainActor 回写状态。
练习
- 实现
@MainActorViewModel,async加载 mock 数据 - 用
.task(id:)监听搜索词变化并防抖请求 - 编写
actor Counter演示并发安全自增 - 对比 React
Promise.all与TaskGroup并行加载
小结
async/await 简化异步 + MainActor 保护 UI + Actor 隔离共享状态。 下一课数据持久化。见 swift-ui-essentials。