How do I define a singleton that runs only on the main actor?

I'm trying out Swift Concurrency on a project, and I wanted to isolate all the logic in a singleton to the main actor.

I tried annotating the singleton class with @MainActor and leaving the rest as is (I'm using a common Singleton pattern in Swift, which relies on atomic global variable initialization):

private var manager = FooManager()

@MainActor
final class FooManager {
  class var shared: FooManager { return manager }
}

This fails with a compiler error on the first line:

Call to main actor-isolated initializer 'init()' in a synchronous 
nonisolated context

That error makes perfect sense, but it does leave me wondering if I can do what I want, i.e. use the Swift singleton pattern but keep the singleton isolated to the main actor.

@MainActor
public final class FooManager {
  public static let shared = FooManager()

  init() {}
}
1 Like

Thanks - that does compile, but do I still get the same atomicity guarantees I get from a global variable?

That I cannot answer. As far as I know static properties are all lazy, but if I recall correctly so are global properties, that's as far my knowledge goes here.

That is how a global actor is defined so I would says the answer is yes. swift-evolution/0316-global-actors.md at main · apple/swift-evolution · GitHub

Usually we don’t need to redefine the global actor though. We can just use it.

That's a great point! Since shared is implicitly annotated with @MainActor, no two threads can invoke it simultaneously.