Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An actor is a nominal reference type in Swift designed to provide safe, mutually exclusive access to its mutable state in concurrent environments. By enforcing actor isolation at compile time, actors prevent data races by ensuring that only one task can execute code that accesses or modifies their internal state at any given time. Under the hood, an actor manages a serial executor and a “mailbox” of pending tasks. When multiple concurrent tasks attempt to interact with an actor, the actor serializes these requests, processing them one by one.

Declaration and Syntax

Actors are declared using the actor keyword. They share the same capabilities as classes—they can have properties, methods, initializers, subscripts, and conform to protocols—but they do not support inheritance.
actor StateManager {
    private(set) var count: Int = 0
    
    func increment() {
        count += 1
    }
}

Actor Isolation and Access Rules

The core mechanism of an actor is actor isolation. The Swift compiler enforces strict rules regarding how data inside an actor is accessed:
  1. Internal Access (Synchronous): Code executing inside the actor (e.g., within its own methods) can read and mutate its properties synchronously.
  2. Cross-Actor Access (Asynchronous): Code executing outside the actor must interact with the actor asynchronously using the await keyword. This is because the calling task may need to be suspended until the actor’s executor is free to process the request.
let manager = StateManager()

Task {
    // Cross-actor mutation requires 'await'
    await manager.increment()
    
    // Cross-actor reading of isolated state requires 'await'
    let currentCount = await manager.count
}

The nonisolated Keyword

By default, all properties and methods of an actor are isolated to that actor. However, immutable state (declared with let) is implicitly safe to access concurrently. For methods or computed properties that do not access isolated mutable state, you can explicitly opt out of actor isolation using the nonisolated keyword. A nonisolated member can be accessed synchronously from outside the actor.
actor Configuration {
    let environment: String
    var retryLimit: Int
    
    init(environment: String, retryLimit: Int) {
        self.environment = environment
        self.retryLimit = retryLimit
    }
    
    // Opts out of actor isolation
    nonisolated func description() -> String {
        return "Environment: \(environment)" 
        // Cannot access `retryLimit` here without an error
    }
}

let config = Configuration(environment: "Production", retryLimit: 3)
// Synchronous access permitted
let desc = config.description() 

Global Actors

Swift provides the @globalActor attribute to define singleton actors that can isolate state and operations across different types and functions scattered throughout a codebase. The most prominent built-in global actor is @MainActor, which binds execution to the main dispatch queue (the main thread). Applying a global actor attribute to a declaration isolates it to that specific actor’s executor.
@MainActor
class InterfaceController {
    var isVisible: Bool = false
    
    func updateVisibility() {
        isVisible = true
    }
}

Actor Reentrancy

A critical architectural characteristic of Swift actors is that they are reentrant. If an actor executes an asynchronous call (await) within its own isolated context, the actor’s execution is suspended. During this suspension point, the actor’s executor is yielded, allowing it to process other pending tasks in its mailbox. While this prevents deadlocks, it means the actor’s isolated state may mutate between the suspension point and the resumption of the original task. Developers must not assume that isolated state remains unchanged across an await boundary within an actor.
Master Swift with Deep Grasping Methodology!Learn More