One Logo Pool Ball
Distributed · IOS API REFERENCE

DistributedActor

protocol · iOS 16.0+ · SDK 27.1

protocol DistributedActor : AnyObject, Hashable, Identifiable, Sendable

Common protocol to which all distributed actors conform implicitly. The `DistributedActor` protocol generalizes over all distributed actor types. Distributed actor types implicitly conform to this protocol. It is not possible to conform to this protocol by any other declaration other than a `distributed actor`. It is possible to require a type to conform to the ``DistributedActor`` protocol by refining it with another protocol, or by using a generic constraint. ## Synthesized properties For every concrete distributed actor declaration, the compiler synthesizes two properties: `actorSystem` and `id`. They witness the ``actorSystem`` and ``id`` protocol requirements of the ``DistributedActor`` protocol. It is not possible to implement these properties explicitly in user code. These properties are `nonisolated` and accessible even if the instance is _remote_, because _all_ distributed actor references must store the actor system remote calls will be delivered through, as well as the id identifying the target of those calls. ## The ActorSystem associated type Every distributed actor must declare what type of actor system it is part of by implementing the ``ActorSystem`` associated type requirement. This causes a number of other properties of the actor to be inferred: - the ``SerializationRequirement`` that will be used at compile time to verify `distributed` target declarations are well formed, - if the distributed actor is `Codable`, based on the ``id`` being Codable or not, - the type of the ``ActorSystem`` accepted in the synthesized default initializer. A distributed actor must declare what type of actor system it is ready to work with by fulfilling the ``ActorSystem`` type member requirement: ```swift distributed actor Greeter { typealias ActorSystem = GreetingSystem // which conforms to DistributedActorSystem func greet() -> String { "Hello!" } } ``` ### The DefaultDistributedActorSystem type alias Since it is fairly common to only be using one specific type of actor system within a module or entire codebase, it is possible to declare the default type of actor system all distributed actors will be using in a module by declaring a `DefaultDistributedActorSystem` module wide typealias: ```swift import Distributed import AmazingActorSystemLibrary typealias DefaultDistributedActorSystem = AmazingActorSystem distributed actor Greeter {} // ActorSystem == AmazingActorSystem ``` This declaration makes all `distributed actor` declarations that do not explicitly specify an ``ActorSystem`` type alias to assume the `AmazingActorSystem` as their `ActorSystem`. It is possible for a specific actor to override the system it is using, by declaring an ``ActorSystem`` type alias as usual: ```swift typealias DefaultDistributedActorSystem = AmazingActorSystem distributed actor Amazing { // ActorSystem == AmazingActorSystem } distributed actor Superb { typealias ActorSystem = SuperbActorSystem } ``` In general the `DefaultDistributedActorSystem` should not be declared public, as picking the default should be left up to each specific module of a project. ## Default initializer While classes and actors receive a synthesized *argument-free default initializer* (`init()`), distributed actors synthesize a default initializer that accepts a distributed actor system the actor is part of: `init(actorSystem:)`. The accepted actor system must be of the `Self.ActorSystem` type, which must conform to the ``DistributedActorSystem`` protocol. This is required because distributed actors are always managed by a concrete distributed actor system and cannot exist on their own without one. It is possible to explicitly declare a parameter-free initializer (`init()`), however the `actorSystem` property still must be assigned a concrete actor system instance the actor shall be part of. In general it is recommended to always have an `actorSystem` parameter as the last non-defaulted non-closure parameter in every actor's initializer parameter list. This way it is simple to swap in a "test actor system" instance in unit tests, and avoid relying on global state which could make testing more difficult. ## Implicit properties Every concrete `distributed actor` type receives two synthesized properties, which implement the protocol requirements of this protocol: `id` and `actorSystem`. ### Property: Actor System The ``actorSystem`` property is an important part of every distributed actor's lifecycle management. Both initialization as well as de-initialization require interactions with the actor system, and it is the actor system that handles all remote interactions of an actor, by both sending or receiving remote calls made on the actor. The ``actorSystem`` property must be assigned in every designated initializer of a distributed actor explicitly. It is highly recommended to make it a parameter of every distributed actor initializer, and simply forward the value to the stored property, like this: ```swift init(name: String, actorSystem: Self.ActorSystem) { self.name = name self.actorSystem = actorSystem } ``` Forgetting to initialize the actor system, will result in a compile time error: ```swift // BAD init(name: String, actorSystem: Self.ActorSystem) { self.name = name // BAD, will cause compile-time error; the `actorSystem` was not initialized. } ``` ### Property: Distributed Actor Identity ``id`` is assigned by the actor system during the distributed actor's initialization, and cannot be set or mutated by the actor itself. ``id`` is the effective identity of the actor, and is used in equality checks, as well as the actor's synthesized `Codable` conformance if the ``id`` type conforms to `Codable`. ## Automatic Conformances ### Hashable and Identifiable conformance Every distributed actor conforms to the `Hashable` and `Identifiable` protocols. Its identity is strictly driven by its ``id``, and therefore hash and equality implementations directly delegate to the ``id`` property. Comparing a local distributed actor instance and a remote reference to it (both using the same ``id``) always returns true, as they both conceptually point at the same distributed actor. It is not possible to implement these protocols relying on the actual actor's state, because it may be remote and the state may not be available. In other words, since these protocols must be implemented using `nonisolated` functions, only `nonisolated` `id` and `actorSystem` properties are accessible for their implementations. ### Implicit Codable conformance If created with an actor system whose ``DistributedActorSystem/ActorID`` is `Codable`, the compiler will synthesize code for the concrete distributed actor to conform to `Codable` as well. This is necessary to support distributed calls where the `SerializationRequirement` is `Codable` and thus users may want to pass actors as arguments to remote calls. The synthesized implementations use a single `SingleValueEncodingContainer` to encode/decode the ``id`` property of the actor. The `Decoder` required `Decoder.init(from:)` is implemented by retrieving an actor system from the decoders' `userInfo`, effectively like as follows: ```swift decoder.userInfo[.actorSystemKey] as? ActorSystem The such obtained actor system is then used to ``resolve(id:using:)`` the decoded ``id``. Use the `CodingUserInfoKey.actorSystemKey` to provide the necessary actor system for the decoding initializer when decoding a distributed actor. - SeeAlso: ``DistributedActorSystem``

Members (2)

method · iOS 17.0+

assertIsolated

Swift declaration
nonisolated func assertIsolated(_ message: @autoclosure () -> String = String(), file: StaticString = #fileID, line: UInt = #line)

Stops program execution if the current task is not executing on this actor's serial executor. This function's effect varies depending on the build flag used: * In playgrounds and `-Onone` builds (the default for Xcode's Debug configuration), stops program execution in a debuggable state after printing `message`. * In `-O` builds (the default for Xcode's Release configuration), the isolation check is not performed and there are no effects. - Note: This check is performed against the actor's serial executor, meaning that / if another actor uses the same serial executor--by using that actor's serial executor as its own `Actor.unownedExecutor`--this check will succeed , as from a concurrency safety perspective, the serial executor guarantees mutual exclusion of those two actors. - Parameters: - message: The message to print if the assertion fails. - file: The file name to print if the assertion fails. The default is where this method was called. - line: The line number to print if the assertion fails The default is where this method was called.

method · iOS 17.0+

preconditionIsolated

Swift declaration
nonisolated func preconditionIsolated(_ message: @autoclosure () -> String = String(), file: StaticString = #fileID, line: UInt = #line)

Stops program execution if the current task is not executing on this actor's serial executor. This function's effect varies depending on the build flag used: * In playgrounds and `-Onone` builds (the default for Xcode's Debug configuration), stops program execution in a debuggable state after printing `message`. * In `-O` builds (the default for Xcode's Release configuration), stops program execution. - Note: Because this check is performed against the actor's serial executor, if another actor uses the same serial executor--by using that actor's serial executor as its own `Actor.unownedExecutor`--this check will succeed. From a concurrency safety perspective, the serial executor guarantees mutual exclusion of those two actors. - Parameters: - message: The message to print if the assertion fails. - file: The file name to print if the assertion fails. The default is where this method was called. - line: The line number to print if the assertion fails The default is where this method was called.

Skipped declarations

3 declarations were excluded from these bindings. Each reason comes from the generator or the iOS SDK compiler.

DistributedActor.whenLocal(_:)

This protocol needs associated types that cannot yet cross the bridge.

DistributedActor.asLocalActor

The iOS SDK compiler rejected this binding: distributed actor-isolated property 'asLocalActor' can not be accessed from a nonisolated context

DistributedActor.assumeIsolated(_:file:line:)

This protocol needs associated types that cannot yet cross the bridge.

All Distributed types →