Understanding Swift Actors

Emre Karaoğlu
Appcent
Published in
3 min readMar 15, 2024

Hi, Hello and Welcome! Today we are going to talk about something called “Actor” in Swift Programming Language.

What is an Actor? Why do we use it?

Since Actor is a tough subject let me explain it with a short story;

Imagine this, the teddy bear wanted to play with a shiny red car that was in the playroom. But other teddy bears also want to play with the same car. All the teddy bears kept pulling the red car from each other’s hands. The incident got so bad that before anyone could play with the car properly, all the teddy bears got tired and fell asleep. Then a light appeared and a fairy named Actor came! This fairy created a timetable for all the teddy bears to play with, so that no one could play with their toys without disturbing anyone else.

I hope you get the point. Oh, if you didn’t let me explain it from another perspective.

Class vs Actor

Let us compare the “actor” with something we all know… Classes!

Actors are reference type like Classes,

They both can have properties, methods, initializers etc.

Actors don’t support inheritance at all and don’t support final, override!

Class vs Actor Table

Are you still looking for an explanation? Okay, let me give you theoretical explanation:

Actors are introduced with Swift 5.5 to securely enhance concurrent and parallel programming support. Actors are a special structure designed to manage shared state and ensure data security in a concurrent environment.

Examples

Now, let me give you an example of how to use actors.

Let’s create our Actor:

actor EmployeeActor {
private var salary: Int = 100

func increaseSalary(increase: Int) {
salary += increase
}

func getSalary() -> Int {
return salary
}
}

Now let’s create a Class:

class EmployeeClass {
private var salary: Int = 100

func increaseSalary(increase: Int) {
usleep(1000)
salary += increase
}

func getSalary() -> Int {
usleep(1000)
return salary
}
}

I also add some uSleep to simulate Data Race Conditions for better understanding.

As you can see we did create two type of objects which are almost the same but they doesn’t act same. Swift Actors will ensure that only one piece of code interacts with it at given time.

Then let’s call our Actor and Class:

    override func viewDidLoad() {
super.viewDidLoad()

let employeeActor = EmployeeActor()

increaseSalaryAsyncActor(employee: employeeActor, increase: 50)
increaseSalaryAsyncActor(employee: employeeActor, increase: 100)

let employeeClass = EmployeeClass()

increaseSalaryAsyncClass(employee: employeeClass, increase: 50)
increaseSalaryAsyncClass(employee: employeeClass, increase: 100)

}

func increaseSalaryAsyncActor(employee: EmployeeActor, increase: Int) {
Task {
await employee.increaseSalary(increase: increase)

let newSalary = await employee.getSalary()
print("New salary Actor: \(newSalary)")
}
}

func increaseSalaryAsyncClass(employee: EmployeeClass, increase: Int) {
DispatchQueue.global().async {
employee.increaseSalary(increase: increase)

let newSalary = employee.getSalary()
print("New salary Class: \(newSalary)")
}
}

What would be the output? What do you think? Did you think that outputs of actor and class would be same right? No, unfortunately they aren’t.

Now let’s see the output:

Output

As you can see while our Actor acts as expected which will increases Employee’s salary to 150 then 250, Class says that Employee’s salary is 250 and 250. That is a basic example of a data race. Hope you can understand the difference between them.

I tried to keep it as simple as possible for beginners to the subject. I hope you understand the point. If you have further questions please comment below, I’d like to help.

--

--

Emre Karaoğlu
Appcent
Writer for

Hey, it's a me Emre! Join me in my iOS developer journey.