Swift Actor with Sample

GitaekLee
3 min readFeb 15, 2023

Swift actors are a new concurrency feature introduced in Swift 5.5 that provide a safe and efficient way to manage shared mutable state. Actors are a type of object that can be accessed concurrently from multiple threads, but ensure that access to their mutable state is serialized and thread-safe. In this blog, we’ll explore the benefits of actors and provide a sample code to demonstrate their usage.

The Benefits of Actors

Traditionally, concurrent programming in Swift has been achieved using locks, semaphores, and other low-level synchronization primitives. While these mechanisms can be effective, they are prone to problems such as deadlocks, race conditions, and other synchronization issues that can be difficult to diagnose and debug.

Actors provide a higher-level abstraction that can simplify concurrent programming by encapsulating shared mutable state and providing a well-defined communication mechanism between threads. By using actors, developers can avoid many of the pitfalls associated with traditional concurrency mechanisms and build more robust and scalable applications.

Some of the key benefits of actors include:

Safe and predictable concurrency: Actors provide a thread-safe and predictable way to manage shared mutable state. By using actors, developers can avoid many of the common concurrency pitfalls such as race conditions and deadlocks.

Performance: Actors are designed to be highly efficient and can provide excellent performance in multi-threaded applications. They are optimized for low-overhead communication between threads, making them ideal for high-performance applications.

Code clarity: By encapsulating shared mutable state within actors, the code becomes easier to understand and maintain. Actors provide a clear separation of concerns between threads, making it easier to reason about concurrent behavior.

Sample Code

Let’s take a look at a sample code that demonstrates how to use actors in Swift.

actor BankAccount {
private var balance: Int

init(initialBalance: Int) {
balance = initialBalance
}

func deposit(amount: Int) {
balance += amount
}

func withdraw(amount: Int) -> Int {
if balance >= amount {
balance -= amount
return amount
} else {
let available = balance
balance = 0
return available
}
}

func balanceConfig() -> Int {
return self.balance
}
}

func transfer(amount: Int, from: BankAccount, to: BankAccount) async throws {
let available = await from.withdraw(amount: amount)
await to.deposit(amount: available)
}

let account1 = BankAccount(initialBalance: 100)
let account2 = BankAccount(initialBalance: 50)

func update() async {
Task {
try await transfer(amount: 75, from: account2, to: account1)
print("Transfer complete :: account2 => account1: 75 ")
}

Task {
try await transfer(amount: 50, from: account1, to: account2)
print("Transfer complete :: account1 => account2 : 50 ")
}
}

func config() async {
Task {
let balance1 = await account1.balanceConfig() // actor method
let balance2 = await account2.balanceConfig() // actor method

print("account1 balance1 = \(balance1) , account2 balance2 = \(balance2)")
}
}

print("start")
await update()
await config()

In this example, we define a BankAccount actor that has a mutable balance property. The actor provides two methods: deposit and withdraw, which modify the balance property in a thread-safe manner. We then define a transfer function that transfers money from one account to another using the withdraw and deposit methods. Finally, we create two tasks that transfer money between the two accounts and print a message when the transfer is complete.

Note that the transfer function uses the await keyword to suspend execution until the withdraw method returns. This ensures that the deposit method is not called until the withdrawal is complete, even if the tasks executing the two methods are running concurrently on different threads.

Conclusion

In conclusion, Swift actors provide a safe and efficient way to manage shared mutable state in multi-threaded applications. Actors provide a clear separation of concerns between threads and help to avoid many of the pitfalls associated with traditional concurrency mechanisms

--

--

GitaekLee

Full-Stack Software Engineer Fellow @Formation / ex. @Zum internet, @doinglab