Bird
Raised Fist0
Swiftprogramming~20 mins

Actors vs locks decision in Swift - Practice Questions

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Concurrency Mastery: Actors vs Locks
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of concurrent access with actor
What will be the output of this Swift code using an actor to protect shared state?
Swift
actor Counter {
    var value = 0
    func increment() {
        value += 1
    }
    func getValue() -> Int {
        return value
    }
}

let counter = Counter()

Task {
    await counter.increment()
}

Task {
    await counter.increment()
}

Task {
    let val = await counter.getValue()
    print(val)
}

// Wait a moment to let tasks finish
Thread.sleep(forTimeInterval: 0.1)
A2
B0
C1
DCompilation error
Attempts:
2 left
💡 Hint
Actors serialize access to their internal state, so increments are safe.
❓ Predict Output
intermediate
2:00remaining
Output of concurrent access with lock
What will be the output of this Swift code using a lock to protect shared state?
Swift
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
    }
}

let counter = Counter()

DispatchQueue.global().async {
    counter.increment()
}

DispatchQueue.global().async {
    counter.increment()
}

DispatchQueue.global().async {
    print(counter.getValue())
}

// Wait a moment to let async tasks finish
Thread.sleep(forTimeInterval: 0.1)
A0
B2
C1
DRuntime error
Attempts:
2 left
💡 Hint
The lock ensures only one thread changes the value at a time.
🧠 Conceptual
advanced
2:00remaining
Choosing between actors and locks
Which of the following is the best reason to choose actors over locks in Swift concurrency?
AActors allow multiple threads to write to the same variable simultaneously for better performance.
BActors are only useful for UI updates and not for data protection.
CActors automatically serialize access to their state, reducing risk of deadlocks and race conditions.
DActors require manual lock management, giving more control over concurrency.
Attempts:
2 left
💡 Hint
Think about safety and ease of use in concurrency.
❓ Predict Output
advanced
2:00remaining
Output difference between actor and lock with async delay
What is the output of this Swift code comparing actor and lock with async delay?
Swift
actor AsyncCounter {
    var value = 0
    func increment() async {
        let current = value
        try? await Task.sleep(nanoseconds: 100_000_000) // 0.1 sec
        value = current + 1
    }
    func getValue() -> Int {
        return value
    }
}

class LockCounter {
    private var value = 0
    private let lock = NSLock()
    func increment() {
        lock.lock()
        let current = value
        Thread.sleep(forTimeInterval: 0.1)
        value = current + 1
        lock.unlock()
    }
    func getValue() -> Int {
        lock.lock()
        let val = value
        lock.unlock()
        return val
    }
}

let actorCounter = AsyncCounter()
let lockCounter = LockCounter()

Task {
    await actorCounter.increment()
}
Task {
    await actorCounter.increment()
}

DispatchQueue.global().async {
    lockCounter.increment()
}
DispatchQueue.global().async {
    lockCounter.increment()
}

// Wait for increments
Thread.sleep(forTimeInterval: 0.3)

Task {
    print("ActorCounter: \(await actorCounter.getValue())")
    print("LockCounter: \(lockCounter.getValue())")
}
AActorCounter: 2\nLockCounter: 2
BActorCounter: 1\nLockCounter: 2
CActorCounter: 2\nLockCounter: 1
DActorCounter: 1\nLockCounter: 1
Attempts:
2 left
💡 Hint
Actors serialize async calls, locks serialize threads.
🧠 Conceptual
expert
2:00remaining
When to prefer locks over actors
In which scenario is using locks preferred over actors in Swift concurrency?
AWhen you want to isolate state in a single-threaded context automatically.
BWhen you want automatic serialization of state without manual lock management.
CWhen you want to avoid any blocking and use only asynchronous code.
DWhen you need fine-grained control over locking multiple resources simultaneously to avoid deadlocks.
Attempts:
2 left
💡 Hint
Think about complex locking scenarios involving multiple resources.

Practice

(1/5)
1. Which of the following best describes the main advantage of using actors in Swift concurrency?
easy
A. They automatically protect data from concurrent access without manual locking.
B. They provide manual control over thread synchronization using locks.
C. They are used only for UI updates in Swift applications.
D. They require explicit lock management to avoid race conditions.

Solution

  1. Step 1: Understand what actors do in Swift concurrency

    Actors automatically serialize access to their mutable state, preventing data races without manual locks.
  2. Step 2: Compare actors with locks

    Locks require manual management to protect data, while actors handle this automatically.
  3. Final Answer:

    They automatically protect data from concurrent access without manual locking. -> Option A
  4. Quick Check:

    Actors = automatic data protection [OK]
Hint: Actors handle concurrency safety automatically, unlike manual locks. [OK]
Common Mistakes:
  • Thinking actors require manual lock management.
  • Confusing actors with UI-only components.
  • Assuming locks are always safer than actors.
2. Which of the following is the correct way to declare an actor in Swift?
easy
A. class MyActor {}
B. actor MyActor {}
C. struct MyActor {}
D. lock MyActor {}

Solution

  1. Step 1: Recall Swift syntax for actors

    Actors are declared using the keyword actor followed by the name and braces.
  2. Step 2: Check each option

    actor MyActor {} uses actor MyActor {}, which is the correct syntax. Others use class, struct, or invalid keyword.
  3. Final Answer:

    actor MyActor {} -> Option B
  4. Quick Check:

    Actor declaration uses 'actor' keyword [OK]
Hint: Actors start with 'actor' keyword, not class or struct. [OK]
Common Mistakes:
  • Using 'class' or 'struct' instead of 'actor'.
  • Trying to use 'lock' keyword which doesn't exist.
  • Forgetting braces after actor name.
3. Consider this Swift code snippet:
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?
medium
A. Compilation error due to missing locks
B. 0
C. 1
D. Runtime crash due to data race

Solution

  1. Step 1: Understand actor's behavior with state

    The actor serializes access to its state, so increment() safely updates value.
  2. Step 2: Analyze the code execution

    The increment() method increases value from 0 to 1, then print outputs the updated value.
  3. Final Answer:

    1 -> Option C
  4. Quick Check:

    Actor state updated safely = 1 [OK]
Hint: Actors serialize access, so state updates are safe and visible. [OK]
Common Mistakes:
  • Expecting 0 because of async call.
  • Thinking a lock is needed causing error.
  • Assuming data race causes crash.
4. This Swift code uses a lock to protect shared data:
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?
medium
A. It can cause a deadlock if increment() is called recursively.
B. It will not compile because NSLock is not imported.
C. It does not protect the value variable from concurrent access.
D. It uses actors incorrectly instead of locks.

Solution

  1. Step 1: Analyze lock usage in increment()

    The method locks before incrementing and unlocks after, but if increment() calls itself, it will try to lock again without unlocking first.
  2. Step 2: Understand deadlock risk

    NSLock is not reentrant, so recursive locking causes deadlock, freezing the program.
  3. Final Answer:

    It can cause a deadlock if increment() is called recursively. -> Option A
  4. Quick Check:

    NSLock + recursion = deadlock risk [OK]
Hint: NSLock is not reentrant; recursive locks cause deadlock. [OK]
Common Mistakes:
  • Assuming NSLock is reentrant.
  • Thinking code won't compile without import (usually imported).
  • Confusing actors with locks in this context.
5. You have a Swift app that needs to update a shared cache from multiple concurrent tasks. You want safety and simplicity without manual lock management. Which approach should you choose?
hard
A. Use a global variable without any synchronization.
B. Use NSLock to manually lock and unlock around cache updates.
C. Use DispatchQueue.sync to serialize access without actors.
D. Use an actor to manage the cache state and provide async methods.

Solution

  1. Step 1: Identify requirements for safety and simplicity

    Actors provide automatic data protection and simplify concurrency without manual locks.
  2. Step 2: Compare options

    NSLock requires manual lock management, global variable is unsafe, DispatchQueue.sync can block threads and is more complex.
  3. Final Answer:

    Use an actor to manage the cache state and provide async methods. -> Option D
  4. Quick Check:

    Actors = safe + simple concurrency [OK]
Hint: Actors simplify concurrency by managing safety automatically. [OK]
Common Mistakes:
  • Choosing manual locks for simplicity.
  • Ignoring thread safety with global variables.
  • Using DispatchQueue.sync causing potential deadlocks.
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard