跳到主要内容

Concurrency in Swift

Introduction

Swift's modern concurrency model provides powerful tools for writing asynchronous code that is both safe and efficient. This guide covers async/await syntax, actors, and structured concurrency.

Async/Await

Basic Syntax

func fetchUserData() async throws -> User {
let data = try await URLSession.shared.data(from: userURL)
return try JSONDecoder().decode(User.self, from: data)
}

// Using async function
async {
do {
let user = try await fetchUserData()
print(user.name)
} catch {
print("Error: \(error)")
}
}

Task Management

// Creating a task
let task = Task {
await performLongOperation()
}

// Task groups
await withTaskGroup(of: Result.self) { group in
for id in ids {
group.addTask {
await processItem(id)
}
}
}

Actors

Definition and Usage

actor BankAccount {
private var balance: Decimal

init(initialBalance: Decimal) {
self.balance = initialBalance
}

func deposit(_ amount: Decimal) {
balance += amount
}

func withdraw(_ amount: Decimal) throws {
guard balance >= amount else {
throw BankError.insufficientFunds
}
balance -= amount
}
}

// Using an actor
let account = BankAccount(initialBalance: 1000)
await account.deposit(500)
try await account.withdraw(200)

Structured Concurrency

Task Trees

func processImages(_ urls: [URL]) async throws -> [ProcessedImage] {
try await withThrowingTaskGroup(of: ProcessedImage.self) { group in
for url in urls {
group.addTask {
let data = try await downloadImage(from: url)
return try await processImage(data)
}
}

var results: [ProcessedImage] = []
for try await image in group {
results.append(image)
}
return results
}
}

Best Practices

  1. Use structured concurrency for better code organization
  2. Implement proper error handling in async contexts
  3. Avoid data races with actors
  4. Consider task priorities and cancellation
  5. Profile concurrent code for performance

Common Patterns

Async Sequences

for await element in asyncSequence {
process(element)
}

// Custom async sequence
struct NumberGenerator: AsyncSequence {
typealias Element = Int

struct AsyncIterator: AsyncIteratorProtocol {
var current = 0

mutating func next() async -> Int? {
guard current < 10 else { return nil }
current += 1
return current
}
}

func makeAsyncIterator() -> AsyncIterator {
AsyncIterator()
}
}

Next Steps

  1. Learn about Package Management
  2. Study Performance Optimization
  3. Explore Security