Swift Global Actors

Actors are a new kind of reference type that protect their instance data from concurrent access through actor isolation — ensures at compile time that all accesses to that instance data go through a synchronization mechanism that serializes execution.

Global actors extend the notion of actor isolation outside of a single actor type, so that global state (and the functions that access it) can benefit from actor isolation, even if the state and functions are scattered across many different types, functions and modules.

Global actors make it possible to safely work with global variables in a concurrent program, as well as modeling other global program constraints such as code that must only execute on the main thread.

Global actors also provide a means to eliminate data races on global and static variables, allowing access to such variables to be synchronized via a global actor.

A global actor is a type (struct, enum, actor, or final class) that has the @globalActor attribute and contains a static property named shared that provides a shared instance of an actor.

@globalActor
public struct SomeGlobalActor {
  public actor MyActor {}
  public static let shared = MyActor()
}

The shared instance is a globally-unique actor instance that becomes synonymous with the global actor type, and will be used for synchronizing access to any code or data that is annotated with the global actor.

The main actor is a global actor that describes the main thread:

@globalActor
public actor MainActor {
  public static let shared = MainActor(...)
}

A global actor is a globally-unique actor identified by a type. Any declaration can state that it is actor-isolated to that particular global actor by naming the global actor type as an attribute.

The declaration can only be synchronously accessed from another declaration on the same global actor, but can be asynchronously accessed from elsewhere.

@MainActor var globalTextSize: Int

@MainActor func increaseTextSize() {
  globalTextSize += 2   // same actor, can be accessed synchronously
}

func notOnTheMainActor() async {
  globalTextSize = 12 // error: isolated to MainActor, cannot call synchronously
  increaseTextSize() // error: isolated to MainActor, cannot call synchronously
  await increaseTextSize() // asynchronous call hops over to the main thread
}