Swift并发

Mattakushi4322026-10-26查看 1226复制 996

何时激活:异步/等待、参与者、任务、结构化并发、MainActor、Swift 中的异步序列

Download (.md)

📘如何使用这个技能

  1. 1
    复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
  2. 2
    打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
  3. 3
    粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
  4. 4
    直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景

💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。

SKILL.md4786 chars
---
name: swift-concurrency
description: "When to activate: async/await, actors, tasks, structured concurrency, MainActor, async sequences in Swift"
origin: zakr
metadata:
  namespace: zakr/devtools-pack
  version: 1.0.0
  category: engineering
  language: swift
  platforms: [claude-code, codex, gemini-cli, cursor, aider, windsurf]
---

# Swift Concurrency

## async/await Basics

```swift
// Mark async functions with async; call them with await
func loadUser(id: UUID) async throws -> User {
    let url = URL(string: "https://api.example.com/users/\(id)")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

// Call from sync context via Task
Task {
    do {
        let user = try await loadUser(id: currentID)
        await MainActor.run { self.user = user }
    } catch {
        await MainActor.run { self.errorMessage = error.localizedDescription }
    }
}
```

## Structured Concurrency with TaskGroup

```swift
func loadFeed(userIDs: [UUID]) async throws -> [User] {
    try await withThrowingTaskGroup(of: User.self) { group in
        for id in userIDs {
            group.addTask { try await loadUser(id: id) }
        }
        var users: [User] = []
        for try await user in group {
            users.append(user)
        }
        return users
    }
}
```

## async let — Parallel Independent Operations

```swift
func loadProfile(id: UUID) async throws -> Profile {
    async let user    = loadUser(id: id)
    async let posts   = loadPosts(userID: id)
    async let friends = loadFriends(userID: id)

    // All three start concurrently; await collects results
    return Profile(
        user:    try await user,
        posts:   try await posts,
        friends: try await friends
    )
}
```

## Actors

Actors protect mutable state from concurrent access.

```swift
actor Cache<Key: Hashable, Value> {
    private var store: [Key: Value] = [:]

    func get(_ key: Key) -> Value? { store[key] }

    func set(_ key: Key, value: Value) { store[key] = value }

    func remove(_ key: Key) { store.removeValue(forKey: key) }
}

// Accessing actor state requires await
let cache = Cache<String, Data>()
await cache.set("key", value: data)
let cached = await cache.get("key")
```

## @MainActor

Annotate types or methods that must run on the main thread.

```swift
@MainActor
class ViewModel: ObservableObject {
    @Published var items: [Item] = []
    @Published var isLoading = false

    func load() async {
        isLoading = true
        defer { isLoading = false }
        items = try! await fetchItems()  // already on MainActor
    }
}

// Or annotate individual methods
class DataService {
    @MainActor func updateUI(with data: [Item]) {
        // safe to touch UIKit/SwiftUI state here
    }
}
```

## AsyncSequence

```swift
// Consuming an AsyncSequence
for await line in url.lines {  // URLSession.lines is an AsyncSequence
    processLine(line)
}

// Custom AsyncSequence via AsyncStream
func timerStream(interval: Duration) -> AsyncStream<Date> {
    AsyncStream { continuation in
        let timer = Timer.scheduledTimer(withTimeInterval: interval.timeInterval, repeats: true) { _ in
            continuation.yield(Date())
        }
        continuation.onTermination = { _ in timer.invalidate() }
    }
}

for await tick in timerStream(interval: .seconds(1)) {
    print("Tick: \(tick)")
}
```

## Task Cancellation

```swift
func fetchWithCancellation(url: URL) async throws -> Data {
    try Task.checkCancellation()  // throws CancellationError if cancelled

    let (data, _) = try await URLSession.shared.data(from: url)

    try Task.checkCancellation()  // check again after suspension
    return data
}

// Cancel from the outside
let task = Task { try await fetchWithCancellation(url: url) }
task.cancel()  // cooperative cancellation
```

## Sendable

```swift
// Value types are Sendable by default (struct, enum with Sendable storage)
struct Message: Sendable {
    let id: UUID
    let text: String
}

// Classes need explicit conformance or @unchecked
final class Config: @unchecked Sendable {
    private let lock = NSLock()
    private var _value: Int = 0
    var value: Int {
        get { lock.withLock { _value } }
        set { lock.withLock { _value = newValue } }
    }
}
```

## Common Anti-Patterns

- **`DispatchQueue.main.async` in async code** — use `await MainActor.run { }` or `@MainActor`
- **Unstructured tasks everywhere** — prefer `async let` and `TaskGroup` for structured concurrency
- **Not checking cancellation** — call `Task.checkCancellation()` at suspension points
- **Calling actor methods with `DispatchQueue`** — actors replace queues; don't mix
- **`@unchecked Sendable` without proper locking** — audit every instance
来源:skillsdirectory

评论0

登录后参与评论

还没有评论,来抢沙发吧