📖 Scenario: Imagine you have a shared bank account accessed by multiple people at the same time. Without rules, two people might try to withdraw money simultaneously, causing errors. In Swift, actors help manage this by making sure only one person accesses the account at a time, preventing mistakes called data races.
🎯 Goal: You will create a simple BankAccount actor that safely updates the balance. You will then try to update the balance from multiple tasks and see how actors prevent data races.
📋 What You'll Learn
Create an actor called BankAccount with a balance property set to 100
Add a function withdraw(amount:) inside the actor to subtract from balance
Create a constant account as an instance of BankAccount
Call withdraw(amount: 30) twice concurrently using Task
Print the final balance after both withdrawals
💡 Why This Matters
🌍 Real World
Actors are used in apps where multiple parts of the program need to safely share and update data, like bank apps, games, or messaging apps.
💼 Career
Understanding actors and data race prevention is important for Swift developers working on safe, concurrent applications.
Progress0 / 4 steps
1
Create the BankAccount actor with initial balance
Create an actor called BankAccount with a variable balance set to 100 inside it.
Swift
Hint
Use the actor keyword and define var balance = 100 inside it.
2
Add a withdraw function to the actor
Inside the BankAccount actor, add a function called withdraw(amount: Int) that subtracts amount from balance.
Swift
Hint
Define a function withdraw(amount: Int) that reduces balance by amount.
3
Create an instance and withdraw concurrently
Create a constant account as an instance of BankAccount. Then start two concurrent Tasks that each call await account.withdraw(amount: 30).
Swift
Hint
Create let account = BankAccount() and use two Task blocks calling await account.withdraw(amount: 30).
4
Print the final balance after withdrawals
Add a Task that waits a moment and then prints await account.balance to show the final balance.
Swift
Hint
Use Task.sleep to wait briefly, then print await account.balance.
Practice
(1/5)
1. Why do Swift actors help prevent data races?
easy
A. They duplicate data for each task automatically.
B. They allow only one task to access their data at a time.
C. They run all tasks in parallel without waiting.
D. They disable concurrency features in Swift.
Solution
Step 1: Understand what a data race is
A data race happens when multiple tasks try to change the same data at the same time.
Step 2: How actors manage access
Actors allow only one task to access or change their data at once, preventing simultaneous changes.
Final Answer:
They allow only one task to access their data at a time. -> Option B
Quick Check:
Actors serialize access = prevent data races [OK]
Hint: Actors serialize access to data, so no simultaneous changes happen [OK]
Common Mistakes:
Thinking actors duplicate data for each task
Believing actors run tasks in parallel without control
Assuming actors disable concurrency features
2. Which is the correct way to call an actor's method in Swift?
easy
A. actorInstance.method()
B. actorInstance.method.await()
C. await actorInstance.method()
D. async actorInstance.method()
Solution
Step 1: Recall actor method call syntax
Actor methods are asynchronous and require the await keyword to call.
Step 2: Identify correct usage
The correct syntax is to write await actorInstance.method() to wait for the method to complete.
Final Answer:
await actorInstance.method() -> Option C
Quick Check:
Use await before actor calls [OK]
Hint: Always use await before calling actor methods [OK]
Common Mistakes:
Calling actor methods without await
Using async keyword incorrectly in call
Placing await after method call
3. What will be the output of this Swift code?
actor Counter {
var value = 0
func increment() {
value += 1
}
}
let counter = Counter()
Task {
await counter.increment()
print(await counter.value)
}
medium
A. 0
B. Runtime crash
C. 1
D. Compilation error
Solution
Step 1: Understand actor property access
Accessing actor properties from outside requires await because it is asynchronous.
Step 2: Trace the code execution
The increment() method increases value by 1, but since increment() is not marked as async, calling it with await causes a compilation error.
Final Answer:
Compilation error -> Option D
Quick Check:
increment() must be async to be awaited [OK]
Hint: increment() must be async to be awaited [OK]
Common Mistakes:
Forgetting await when accessing actor property
Expecting 0 because of missing synchronization
Assuming increment is synchronous
4. Identify the error in this Swift actor code:
actor BankAccount {
var balance = 0
func deposit(amount: Int) {
balance += amount
}
}
let account = BankAccount()
Task {
account.deposit(amount: 100)
print(await account.balance)
}
medium
A. Missing await before deposit call
B. balance should be a constant
C. deposit method cannot modify balance
D. print statement should not use await
Solution
Step 1: Check actor method call rules
Calling an actor's method from outside must use await because it's asynchronous.
Step 2: Identify missing await
The code calls account.deposit(amount: 100) without await, causing a compile error.
Final Answer:
Missing await before deposit call -> Option A
Quick Check:
Actor method calls require await [OK]
Hint: Always put await before actor method calls outside actor [OK]
Common Mistakes:
Ignoring await on actor method calls
Thinking balance must be constant
Assuming print can't await actor properties
5. Given this actor code, why does using an actor prevent a data race when multiple tasks call increment()?
actor SafeCounter {
var count = 0
func increment() {
count += 1
}
}
hard
A. Because actor methods run one at a time, queuing calls safely.
B. Because the count variable is copied for each task.
C. Because Swift disables concurrency inside actors.
D. Because increment() is automatically atomic without queuing.
Solution
Step 1: Understand actor method execution
Actor methods run serially, meaning one finishes before the next starts.
Step 2: How this prevents data races
Since calls to increment() are queued and run one by one, simultaneous changes to count cannot happen.
Final Answer:
Because actor methods run one at a time, queuing calls safely. -> Option A
Quick Check:
Actors serialize method calls = no data races [OK]
Hint: Actors queue method calls, so only one runs at a time [OK]
Common Mistakes:
Thinking variables are copied per task
Believing concurrency is disabled inside actors
Assuming increment is atomic without queuing
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.