Actors and locks help keep your program safe when many parts try to use the same data at once. Choosing between them helps avoid mistakes and crashes.
Actors vs locks decision in Swift
actor MyActor {
var count = 0
func increment() {
count += 1
}
}
// Using a lock
class MyClass {
private var count = 0
private let lock = NSLock()
func increment() {
lock.lock()
count += 1
lock.unlock()
}
}Actors are special types that protect their data automatically.
Locks are manual tools you use to protect data by telling when to wait and when to go.
actor Counter {
var value = 0
func increment() {
value += 1
}
}class Counter { private var value = 0 private let lock = NSLock() func increment() { lock.lock() value += 1 lock.unlock() } }
This program shows two ways to protect data: one with an actor and one with a lock. Both count up safely.
import Foundation actor SafeCounter { var count = 0 func increment() { count += 1 } func getCount() -> Int { return count } } class LockedCounter { private var count = 0 private let lock = NSLock() func increment() { lock.lock() count += 1 lock.unlock() } func getCount() -> Int { lock.lock() let current = count lock.unlock() return current } } func testCounters() async { let safeCounter = SafeCounter() let lockedCounter = LockedCounter() // Increment both counters 5 times for _ in 1...5 { await safeCounter.increment() lockedCounter.increment() } let safeCount = await safeCounter.getCount() let lockedCount = lockedCounter.getCount() print("SafeCounter count: \(safeCount)") print("LockedCounter count: \(lockedCount)") } @main struct Main { static func main() async { await testCounters() } }
Actors handle safety automatically, so you write less code and avoid mistakes.
Locks require you to remember to lock and unlock, which can cause bugs if forgotten.
Actors work well with Swift's async/await, making concurrency easier.
Actors protect data automatically and are easier to use with Swift concurrency.
Locks give manual control but need careful handling to avoid errors.
Choose actors for safety and simplicity; use locks when you need fine control.
Practice
actors in Swift concurrency?Solution
Step 1: Understand what actors do in Swift concurrency
Actors automatically serialize access to their mutable state, preventing data races without manual locks.Step 2: Compare actors with locks
Locks require manual management to protect data, while actors handle this automatically.Final Answer:
They automatically protect data from concurrent access without manual locking. -> Option AQuick Check:
Actors = automatic data protection [OK]
- Thinking actors require manual lock management.
- Confusing actors with UI-only components.
- Assuming locks are always safer than actors.
Solution
Step 1: Recall Swift syntax for actors
Actors are declared using the keywordactorfollowed by the name and braces.Step 2: Check each option
actor MyActor {} usesactor MyActor {}, which is the correct syntax. Others use class, struct, or invalid keyword.Final Answer:
actor MyActor {} -> Option BQuick Check:
Actor declaration uses 'actor' keyword [OK]
- Using 'class' or 'struct' instead of 'actor'.
- Trying to use 'lock' keyword which doesn't exist.
- Forgetting braces after actor name.
actor Counter {
var value = 0
func increment() {
value += 1
}
}
let counter = Counter()
Task {
await counter.increment()
print(await counter.value)
}
What will be printed when this code runs?Solution
Step 1: Understand actor's behavior with state
The actor serializes access to its state, soincrement()safely updatesvalue.Step 2: Analyze the code execution
Theincrement()method increasesvaluefrom 0 to 1, thenprintoutputs the updated value.Final Answer:
1 -> Option CQuick Check:
Actor state updated safely = 1 [OK]
- Expecting 0 because of async call.
- Thinking a lock is needed causing error.
- Assuming data race causes crash.
class Counter {
private var value = 0
private let lock = NSLock()
func increment() {
lock.lock()
value += 1
lock.unlock()
}
func getValue() -> Int {
lock.lock()
let val = value
lock.unlock()
return val
}
}
What is a potential problem with this code?Solution
Step 1: Analyze lock usage in increment()
The method locks before incrementing and unlocks after, but ifincrement()calls itself, it will try to lock again without unlocking first.Step 2: Understand deadlock risk
NSLock is not reentrant, so recursive locking causes deadlock, freezing the program.Final Answer:
It can cause a deadlock ifincrement()is called recursively. -> Option AQuick Check:
NSLock + recursion = deadlock risk [OK]
- Assuming NSLock is reentrant.
- Thinking code won't compile without import (usually imported).
- Confusing actors with locks in this context.
Solution
Step 1: Identify requirements for safety and simplicity
Actors provide automatic data protection and simplify concurrency without manual locks.Step 2: Compare options
NSLock requires manual lock management, global variable is unsafe, DispatchQueue.sync can block threads and is more complex.Final Answer:
Use an actor to manage the cache state and provide async methods. -> Option DQuick Check:
Actors = safe + simple concurrency [OK]
- Choosing manual locks for simplicity.
- Ignoring thread safety with global variables.
- Using DispatchQueue.sync causing potential deadlocks.
Ready to prove it?
Pass the test and this pattern moves unknown
