# Swift Concurrency

> Swift modern concurrency with async/await, Task, Actor, Swift 6 strict mode, Sendable, and structured concurrency patterns.

- Skill: `swiftzilla/swift-concurrency` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add swiftzilla/swift-concurrency`
- Raw SKILL.md: https://api.skillmd.com/api/skills/swiftzilla/swift-concurrency/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- License: Proprietary
- Author: swiftzilla (https://skillmd.com/u/swiftzilla)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/swiftzilla/swift-concurrency

---


# Swift Concurrency

This skill covers Swift's modern concurrency features from Swift 5.5 through Swift 6, including async/await, structured concurrency, actors, and Swift 6's strict data-race safety.

## Overview

Swift's modern concurrency model provides a safer, more intuitive way to write asynchronous code. Swift 6 takes this further with **compile-time data-race safety**, turning potential concurrency bugs into compiler errors.

## Available References

### Swift 6 & Strict Concurrency
- [Swift 6 Strict Mode](./references/swift6_strict_mode.md) - Complete concurrency checking, data race prevention
- [Sendable Protocol](./references/sendable.md) - Sendable conformance, @Sendable closures, thread safety
- [Isolation & Actors](./references/isolation.md) - @MainActor, global actors, region-based isolation

### Core Concurrency
- [Async/Await](./references/async_await.md) - Asynchronous functions, Task, TaskGroup, Actor basics

## Swift 6 Highlights

### Strict Concurrency by Default

Swift 6 enforces data-race safety at compile time:

```swift
// ❌ Compile-time error in Swift 6
var globalCounter = 0

func increment() {
    globalCounter += 1  // Error: concurrent access
}

// ✅ Safe with actor isolation
actor Counter {
    private var value = 0
    func increment() { value += 1 }
}
```

### Sendable Protocol

Mark types safe to share across concurrency boundaries:

```swift
struct User: Sendable {
    let id: Int
    let name: String
}

@Sendable func process() async {
    // Captures must be Sendable
}
```

### MainActor & Global Actors

```swift
@MainActor
class ViewModel: ObservableObject {
    @Published var items = [Item]()
}

@globalActor
actor DatabaseActor {
    static let shared = DatabaseActor()
    private init() {}
}
```

## Quick Reference

### Async/Await Basics

```swift
func fetchData() async throws -> Data {
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}
```

### Swift 6 Migration Checklist

- [ ] Enable Swift 6 language mode
- [ ] Enable strict concurrency checking
- [ ] Wrap global mutable state in actors
- [ ] Add Sendable conformance to types
- [ ] Fix non-Sendable captures in @Sendable closures
- [ ] Isolate UI code with @MainActor
- [ ] Audit third-party dependencies

### Running Async Code

```swift
// Fire-and-forget
Task {
    let result = await asyncOperation()
}

// With priority
Task(priority: .background) {
    await heavyComputation()
}

// With cancellation
let task = Task {
    try await longRunningOperation()
}
task.cancel()
```

### Concurrent Operations

```swift
// Async let (parallel await)
async let task1 = fetchUser()
async let task2 = fetchSettings()
let (user, settings) = try await (task1, task2)

// TaskGroup
try await withThrowingTaskGroup(of: Item.self) { group in
    for id in ids {
        group.addTask { try await fetchItem(id: id) }
    }
    return try await group.reduce(into: []) { $0.append($1) }
}
```

### Actor Thread Safety

```swift
actor BankAccount {
    private var balance: Double = 0
    
    func deposit(_ amount: Double) {
        balance += amount
    }
    
    func getBalance() -> Double {
        return balance
    }
}

let account = BankAccount()
await account.deposit(100)
```

### Isolation Boundaries

```swift
// Crossing isolation boundaries
@MainActor
func updateUI() async {
    // On main thread
    let data = await fetchData()  // Switch to non-isolated
    label.text = data  // Back to main thread
}

// Region transfer
func process() async {
    let data = Data()  // Disconnected
    await save(data)   // Transfer to actor
    // ❌ Can't use data here anymore
}
```

## Swift 6 vs Swift 5.x

| Feature | Swift 5.x | Swift 6 |
|---------|-----------|---------|
| Concurrency checking | Warnings | **Errors** |
| Data race safety | Runtime | **Compile-time** |
| Sendable enforcement | Opt-in | **Required** |
| Global variable safety | Warning | **Error** |
| Strict mode | Experimental | **Default** |

## Best Practices

### Swift 6 Best Practices

1. **Enable Swift 6 mode early** - Start migration now
2. **Use actors for shared state** - Default to actors over locks
3. **Design Sendable types** - Make types Sendable from the start
4. **Isolate UI with @MainActor** - All UI code on main thread
5. **Respect isolation regions** - Don't use values after transfer
6. **Leverage compile-time safety** - Let compiler catch data races
7. **Create domain actors** - Custom global actors for heavy work

### General Concurrency

1. **Prefer async/await** - Over completion handlers
2. **Use structured concurrency** - Clear task hierarchies
3. **Handle cancellation** - Check Task.isCancelled
4. **Use value types** - Immutable data is thread-safe
5. **Avoid shared mutable state** - Or protect with actors

## Migration from Completion Handlers

```swift
// Before (Swift 5)
func fetchUser(completion: @escaping (Result<User, Error>) -> Void) {
    URLSession.shared.dataTask(with: url) { data, response, error in
        // Handle result
        completion(result)
    }.resume()
}

// After (Swift 6)
func fetchUser() async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}
```

## Common Swift 6 Errors

| Error | Quick Fix |
|-------|-----------|
| Concurrent access to global | Wrap in actor |
| Non-Sendable in @Sendable | Make type Sendable |
| Actor isolation violation | Add await or change isolation |
| Use after transfer | Use before transfer or copy value |
| Main actor isolation | Add @MainActor annotation |

## Resources

- **Swift Evolution:** https://github.com/apple/swift-evolution
- **SE-0412:** Strict concurrency for global variables
- **SE-0471:** SerialExecutor isolation checking
- **SE-0430:** Sending parameters
- **SE-0414:** Region-based isolation
- **Apple Docs:** https://developer.apple.com/documentation/swift/concurrency
- **SwiftZilla:** https://swiftzilla.dev

## For More Information

Each reference file contains detailed information, code examples, and best practices for specific topics. Visit https://swiftzilla.dev for comprehensive Swift concurrency documentation.

