Swift Concurrency: async/await and Actors

Swift's structured concurrency model with async/await and actors eliminates common threading bugs at compile time.

Key Insights

  • Swift actors provide compile-time data race protection for shared mutable state
  • Structured concurrency with task groups ensures child tasks don’t outlive parents
  • Sendable protocol marks types safe to pass across concurrency boundaries

Actors

actor BankAccount {
    private var balance: Double = 0

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

    func getBalance() -> Double {
        return balance
    }
}

// Access is always async
let account = BankAccount()
await account.deposit(100)
let balance = await account.getBalance()

Task Groups

func fetchAllUsers(ids: [Int]) async throws -> [User] {
    try await withThrowingTaskGroup(of: User.self) { group in
        for id in ids {
            group.addTask { try await fetchUser(id: id) }
        }
        var users: [User] = []
        for try await user in group {
            users.append(user)
        }
        return users
    }
}

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.