ProgramGuru

Actors and isolated mutable state

Actors and isolated mutable state

Several tasks may need to update one attendance register. An actor protects access to its isolated mutable state through Swift’s concurrency rules. This gives a place to organize coordinated state changes instead of sharing an unrestricted mutable class everywhere.

What you’ll learn

  • Access isolated register state through awaited operations.
  • Explain why suspension does not make a multi-step workflow atomic.

Actors and isolated mutable state in the example

  1. Isolated register

    Several tasks may need to update one attendance register.

    Isolated register
  2. Awaited updates

    Access to actor-isolated operations from outside generally requires await because another operation may be in progress.

    Awaited updates
  3. Read total safely

    The two awaited arrivals are completed before reading the total, so the result is two.

    Read total safely
The two awaited arrivals are completed before reading the total, so the result is two. State is private to the actor. This example intentionally orders the calls rather than relying on unpredictable concurrent print statements.

How actors and isolated mutable state works

Access to actor-isolated operations from outside generally requires await because another operation may be in progress. A method with no suspension can update its isolated state as one uninterrupted actor operation, but an actor method can be reentered around suspension points. Actors do not make a multi-await workflow an automatic transaction.

Work through actors and isolated mutable state

Save this complete program as main.swift and run it with the Swift toolchain. Use a toolchain supporting the demonstrated async top-level code.

Swift · complete program

actor Register {
  private var count = 0
  func recordArrival() { count += 1 }
  func total() -> Int { count }
}
let register = Register()
await register.recordArrival()
await register.recordArrival()
print(await register.total())

Expected output

2

Follow the execution

The two awaited arrivals are completed before reading the total, so the result is two. State is private to the actor. This example intentionally orders the calls rather than relying on unpredictable concurrent print statements.

Try this program in the Swift compiler. Paste the complete source above.

Practice: Actors and isolated mutable state

Your task: Does actor isolation guarantee state stays unchanged across every await inside a longer method?

Swift · complete program

actor Register {
  private var count = 0
  func recordArrival() { count += 1 }
  func total() -> Int { count }
}
let register = Register()
await register.recordArrival()
await register.recordArrival()
print(await register.total())

Worked answer

No. Suspension can allow another operation to enter the actor and change state. Recheck assumptions or design a single non-suspending update when a decision must use consistent state.

Recheck assumptions across suspension

Sendable expresses values suitable for crossing concurrency boundaries under their type rules. MainActor is a specific global actor commonly used for UI-related state, not a general instruction to put every operation on the main thread. Keep blocking work out of an actor’s cooperative execution path.

Check your decision

Does actor isolation guarantee state stays unchanged across every await inside a longer method?
Choose one answer. You can try again.

Answer and explanation

No.

No. Suspension can allow another operation to enter the actor and change state. Recheck assumptions or design a single non-suspending update when a decision must use consistent state.

Check the practical consequence

An actor method checks state, awaits another operation, then acts on the old check. What must it consider?
Choose one answer. You can try again.

Answer and explanation

Other operations may have changed actor state during suspension.

Sendable expresses values suitable for crossing concurrency boundaries under their type rules. MainActor is a specific global actor commonly used for UI-related state, not a general instruction to put every operation on the main thread. Keep blocking work out of an actor’s cooperative execution path.

Recheck assumptions across suspension

No. Suspension can allow another operation to enter the actor and change state. Recheck assumptions or design a single non-suspending update when a decision must use consistent state. Sendable expresses values suitable for crossing concurrency boundaries under their type rules.

Further reading: official Swift language guide.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Build a validated student report →