Actors

Actors

Intro

Reference type.
Single threaded.
Much better solution than relying on classes for concurrency.

New Kid on the Block

Reference type just like Class and function but it guarantees exclusive access to its execution environment with independent threads. Of course it does have to maintain references and the reference type checks and all that goody / baddy stuff for updating states across all the layers whenever something changes due to it inherently being of reference type but still great for Swift concurrency manifesto and not worrying about one more extra thing.

SwiftUI ObservableObject conforming classes can be marked with
@MainActor and it just works like magic.
actors | avanderlee

Swift UI

Data model - View Models with : ObservableObject conformance to the class SwiftUIViewModel should be annotated with @MainActor for switching back threads from background to main.
@Publish var propertyValues would be observed in SwiftUI Struct some View so it is very important that UI elements data refresh things happens on Main thread.

Lot of I/O, font rasterization, 60 vs 120 frames, response times, input delay, processing relies on Main thread. UI Kit is built solely on Main Thread to run UI Tasks and make them as efficient as possible. Without any hitches or dropped frames while scrolling or doing highly intensive tasks.

how-to-use-mainactor-to-run-code-on-the-main-queue

important-do-not-use-an-actor-for-your-swiftui-data-models

Global variable as Main actor

Code snippet from the SO post linked below. Interesting things.

One way would be to store the variable within a container (like an enum acting as an abstract namespace) and also isolating this to the main actor.

@MainActor
enum Globals {
  static var foo = Foo()
}

An equally valid way would be to have a "singleton-like" static property on the object itself, which serves the same purpose but without the additional object.

@MainActor
struct Foo {
  static var shared = Foo()
}

You now access the global object via Foo.global.

One thing to note is that this will now be lazily initialized (on the first invocation) rather than immediately initialized. You can however force an initialization early on by making any access to the object.

// somewhere early on
_ = Foo.shared

how-do-i-initialize-a-global-variable-with-mainactor

MainActor

Actor vs MainActor

mainactor-dispatch-main-thread

Functions automatic async

If the instance class is defined as an actor or added a override like @mainActor then this applies it for async / await thread safety

actor CustomClass {
	func doSomething() { }
}

class CustomClass2 {

	@MainActor
	func doSomething() { }
}

@MainActor to annotate those functions to ensure those updates happen on the Main thread. So Swift does some magic under the hood to make that function call async, hence the await

When your View Model conforms to ObservableObject you want to make sure your updates to Published properties happen on the main thread.

Errors

nonisolated main actor references

/git/cloud/apple/Sources/.swift:250:30 Main actor-isolated property 'Track' can not be referenced from a non-isolated context; this is an error in the Swift 6 language mode

You can solve this using here

References

wwdc2021/10133

wwdc2021/10254

wwdc2021/10194

how-to-use-mainactor-to-run-code-on-the-main-queue

advanced-swift-actors-re-entrancy