0Pricing
Swift Academy · Lesson

Actor Isolation and nonisolated

Reason about isolation boundaries.

Actor Isolation and nonisolated is a free Swift Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Actor Isolation?

Actor isolation means an actor’s mutable state can only be touched by code running on that actor.

The runtime serializes access so two tasks never mutate the state simultaneously, eliminating data races.

actor Counter {
    private var value = 0
    func increment() { value += 1 }
}

Calling Into an Actor

From outside the actor, accessing isolated members is asynchronous. You must await because the call may suspend until the actor is free.

let counter = Counter()
func useCounter() async {
    await counter.increment()
}

Inside the Actor: Synchronous

Within the actor’s own methods, you are already isolated, so you access state synchronously—no await needed for self.

actor Counter {
    private var value = 0
    func incrementTwice() {
        value += 1 // synchronous: already isolated
        value += 1
    }
}

nonisolated Members

Mark a member nonisolated when it does not touch mutable state. Such members run synchronously from anywhere, with no await.

This is ideal for computed values built only from immutable data.

actor User {
    let id: Int
    var sessionCount = 0
    init(id: Int) { self.id = id }
    nonisolated var label: String { "User #\(id)" }
}

Why nonisolated Is Safe

A nonisolated member may only read immutable (let) or otherwise Sendable state.

The compiler rejects any attempt to access mutable isolated state from a nonisolated context.

actor User {
    let id: Int
    var sessionCount = 0
    init(id: Int) { self.id = id }
    // Error: cannot read mutable sessionCount here
    // nonisolated var bad: Int { sessionCount }
}

nonisolated and Protocols

nonisolated is essential when an actor conforms to a synchronous protocol. The protocol method cannot be async, so it must avoid isolated state.

actor Item: CustomStringConvertible {
    let name: String
    init(name: String) { self.name = name }
    nonisolated var description: String { "Item: \(name)" }
}

The MainActor

@MainActor is a global actor that isolates code to the main thread. UI updates belong here.

Annotate types, methods, or properties to pin them to the main actor.

@MainActor
final class ViewModel {
    var title = "Hello"
    func refresh() { title = "Updated" }
}

Hopping Between Actors

When you call from one actor to another, the runtime hops executors and suspends. That suspension is exactly where await appears.

actor Database { func load() -> Int { 42 } }
@MainActor
func show(_ db: Database) async {
    let v = await db.load() // hop to db actor
    print(v)               // hop back to main
}

Actor Reentrancy

Actors are reentrant: when a method awaits, the actor may run other queued work before the await resumes.

State you read before an await may have changed after it. Re-check assumptions after suspension points.

actor Store {
    var ready = false
    func prepare() async {
        ready = false
        await Task.yield() // other calls may run here
        ready = true
    }
}

isolated Parameters

A function can take an isolated actor parameter, running its body on that actor without being a member of it.

func bump(on counter: isolated Counter) {
    // runs isolated to counter; synchronous access
}

Global Actors for Subsystems

You can define your own global actor to isolate a whole subsystem (e.g. a rendering pipeline) onto a single executor.

@globalActor
actor RenderActor {
    static let shared = RenderActor()
}
@RenderActor func draw() { }

Quick Check: Isolation

Test your understanding of actor isolation.

Recap: Actor Isolation and nonisolated

Actor isolation serializes access to mutable state; cross-actor calls are async and require await. nonisolated members opt out of isolation but may only read immutable/Sendable state, which is vital for synchronous protocol conformance.

@MainActor pins code to the main thread, actors are reentrant (state can change across await), and global actors isolate whole subsystems. Mastering these rules is the core of safe concurrency.

Frequently asked questions

Is the “Actor Isolation and nonisolated” lesson free?

Yes — the full text of “Actor Isolation and nonisolated” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Actor Isolation and nonisolated”?

Reason about isolation boundaries. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Actor Isolation and nonisolated” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The Data Race Problem
  2. The Sendable Protocol
  3. Actor Isolation and nonisolated
  4. Migrating to Strict Concurrency
← Back to Swift Academy