Swift并发
Mattakushi4322026-10-26查看 1226复制 996
何时激活:异步/等待、参与者、任务、结构化并发、MainActor、Swift 中的异步序列
📘如何使用这个技能
- 1复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
- 2打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
- 3粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
- 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