并发与响应式
GCD、Combine、RxSwift 概览。
35 分钟
并发与响应式
iOS 并发体系:GCD(Grand Central Dispatch)、OperationQueue、async/await,以及响应式框架 Combine(官方)与 RxSwift(社区)。对照 /roadmaps/ios「Concurrency」节点。
学习目标
- 理解 Main Queue vs Background Queue 的分工
- 用 GCD 与 async/await 执行异步任务
- 掌握 Combine 的 Publisher / Subscriber 基础
- 对照 Java 线程池与 React 异步模式
核心概念
GCD 与 Main Actor
import Foundation
func processImages(_ urls: [URL]) async -> [UIImage] {
await withTaskGroup(of: UIImage?.self) { group in
for url in urls {
group.addTask {
guard let data = try? Data(contentsOf: url),
let image = UIImage(data: data) else { return nil }
return image
}
}
var results: [UIImage] = []
for await image in group {
if let image = image { results.append(image) }
}
return results
}
}
// UI 更新必须在主线程
DispatchQueue.main.async {
self.tableView.reloadData()
}
// Swift 5.5+:@MainActor 标记 UI 相关类型
@MainActor
final class LessonViewModel: ObservableObject {
@Published var lessons: [Lesson] = []
func refresh() async {
let fetched = try? await APIClient.shared.get("/lessons", as: [Lesson].self)
lessons = fetched ?? []
}
}
Main Actor 保证 UI 状态变更在主线程;TaskGroup 并行下载类似 Go 的 goroutine 组。
Combine 基础
import Combine
final class SearchViewModel: ObservableObject {
@Published var query = ""
@Published var results: [Track] = []
private var cancellables = Set<AnyCancellable>()
init(repository: TrackRepository) {
$query
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.flatMap { q -> AnyPublisher<[Track], Never> in
guard !q.isEmpty else { return Just([]).eraseToAnyPublisher() }
return repository.searchPublisher(q)
.catch { _ in Just([]) }
.eraseToAnyPublisher()
}
.assign(to: \.results, on: self)
.store(in: &cancellables)
}
}
Combine 提供声明式数据流:debounce、map、flatMap 组合;SwiftUI 的 原生集成 Combine。