iOS第三十二篇 Swift 并发编程
·
# Swift 并发编程完全指南
## 1. 现代并发模型演进
```swift
// 传统GCD方式(已不推荐)
DispatchQueue.global().async {
let data = fetchData()
DispatchQueue.main.async {
updateUI(with: data)
}
}
// Swift 并发方式(推荐)
Task {
let data = await fetchData()
await MainActor.run {
updateUI(with: data)
}
}
2. 核心概念
2.1 async/await 基础
func loadImage(from url: URL) async throws -> UIImage {
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else {
throw ImageError.invalidData
}
return image
}
2.2 Task 系统
// 创建后台任务
let imageTask = Task.detached(priority: .high) {
return try await loadImage(from: remoteURL)
}
// 取消任务
imageTask.cancel()
// 获取结果
do {
let image = try await imageTask.value
} catch {
handleError(error)
}
3. 结构化并发
3.1 TaskGroup 模式
func fetchAllUserData() async throws -> [UserData] {
try await withThrowingTaskGroup(of: UserData.self) { group in
for userId in userIds {
group.addTask {
try await fetchUserData(id: userId)
}
}
var results = [UserData]()
for try await data in group {
results.append(data)
}
return results.sorted { $0.id < $1.id }
}
}
3.2 async let 绑定
async let user = fetchUserProfile()
async let posts = fetchUserPosts()
async let friends = fetchUserFriends()
let profile = try await Profile(
user: await user,
posts: await posts,
friends: await friends
)
4. 数据竞争防护
4.1 Actor 模型
actor BankAccount {
private var balance: Decimal = 0.0
func deposit(_ amount: Decimal) {
balance += amount
}
func withdraw(_ amount: Decimal) throws {
guard balance >= amount else {
throw BankError.insufficientFunds
}
balance -= amount
}
func currentBalance() -> Decimal {
balance
}
}
// 使用示例
let account = BankAccount()
Task {
await account.deposit(1000)
try await account.withdraw(500)
let balance = await account.currentBalance()
print("Current balance: \(balance)")
}
4.2 Sendable 协议
struct User: Sendable {
let id: UUID
let name: String
}
class UnsafeClass: @unchecked Sendable {
private var queue = DispatchQueue(label: "sync.queue")
private var _count = 0
var count: Int {
queue.sync { _count }
}
func increment() {
queue.async { self._count += 1 }
}
}
5. 高级并发模式
5.1 AsyncSequence 处理流数据
func monitorFileChanges() async throws {
let handle = try FileHandle(forReadingFrom: logFileURL)
for try await line in handle.bytes.lines {
if line.contains("ERROR") {
await sendAlert(message: line)
}
}
}
5.2 AsyncStream 自定义异步序列
func locationUpdates() -> AsyncStream<CLLocation> {
AsyncStream { continuation in
let manager = CLLocationManager()
manager.delegate = LocationDelegate(continuation: continuation)
manager.startUpdatingLocation()
continuation.onTermination = { @Sendable _ in
manager.stopUpdatingLocation()
}
}
}
class LocationDelegate: NSObject, CLLocationManagerDelegate {
let continuation: AsyncStream<CLLocation>.Continuation
init(continuation: AsyncStream<CLLocation>.Continuation) {
self.continuation = continuation
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for location in locations {
continuation.yield(location)
}
}
}
6. 性能优化技巧
6.1 任务优先级管理
Task(priority: .userInitiated) {
// 高优先级任务
}
Task(priority: .utility) {
// 后台任务
}
6.2 协作式取消检查
func processLargeDataset() async throws {
try Task.checkCancellation()
for item in dataset {
// 每次迭代检查取消状态
if Task.isCancelled { break }
await processItem(item)
}
}
7. 与现有技术集成
7.1 桥接 GCD 代码
func legacyOperation() async -> Result {
await withCheckedContinuation { continuation in
OldGCDClass.doSomethingAsync { result in
continuation.resume(returning: result)
}
}
}
7.2 Combine 互操作
func fetchPublisher() -> AnyPublisher<Data, Error> {
let task = Task {
try await fetchData()
}
return Future { promise in
Task {
do {
let result = try await task.value
promise(.success(result))
} catch {
promise(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
8. 调试与测试
8.1 运行时检测
@MainActor func updateUI() { /* ... */ }
Task {
await updateUI() // 编译器保证主线程执行
}
8.2 单元测试示例
class AsyncTests: XCTestCase {
func testFetchData() async throws {
let mockService = MockDataService()
let data = try await mockService.fetchData()
XCTAssertFalse(data.isEmpty)
}
func testConcurrentAccess() async {
let counter = CounterActor()
await withTaskGroup(of: Void.self) { group in
for _ in 0..<1000 {
group.addTask { await counter.increment() }
}
}
let count = await counter.value
XCTAssertEqual(count, 1000)
}
}
actor CounterActor {
private(set) var value = 0
func increment() {
value += 1
}
}
9. 实战案例
9.1 图片加载器
actor ImageLoader {
private var cache = [URL: UIImage]()
private var tasks = [URL: Task<UIImage, Error>]()
func loadImage(from url: URL) async throws -> UIImage {
if let cached = cache[url] {
return cached
}
if let existingTask = tasks[url] {
return try await existingTask.value
}
let task = Task<UIImage, Error> {
defer { tasks[url] = nil }
let image = try await downloadImage(from: url)
cache[url] = image
return image
}
tasks[url] = task
return try await task.value
}
private func downloadImage(from url: URL) async throws -> UIImage {
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else {
throw ImageError.invalidData
}
return image
}
}
9.2 网络请求限流
actor RequestLimiter {
private var activeTasks = 0
private let maxConcurrent: Int
private var pendingContinuations = [CheckedContinuation<Void, Never>]()
init(maxConcurrent: Int = 3) {
self.maxConcurrent = maxConcurrent
}
func beginRequest() async {
if activeTasks >= maxConcurrent {
await withCheckedContinuation { continuation in
pendingContinuations.append(continuation)
}
}
activeTasks += 1
}
func endRequest() {
activeTasks -= 1
if !pendingContinuations.isEmpty {
let continuation = pendingContinuations.removeFirst()
continuation.resume()
}
}
}
// 使用示例
let limiter = RequestLimiter()
func makeLimitedRequest() async throws -> Data {
await limiter.beginRequest()
defer { limiter.endRequest() }
return try await URLSession.shared.data(from: url).0
}
10. 资源推荐
-
官方文档:
-
WWDC推荐:
- “Meet async/await in Swift” (WWDC21)
- “Swift concurrency: Behind the scenes” (WWDC21)
- “Visualize and optimize Swift concurrency” (WWDC22)
-
工具链:
- Xcode 13+ 并发调试工具
- Instruments 的 Swift Concurrency 模板
-Xfrontend -validate-tbd-against-ir=none编译选项(解决复杂项目问题)
更多推荐


所有评论(0)