Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A reimplementation of the basics of MainActor. Sample code for https://oleb.net/2022/how-mainactor-works/
import Dispatch
@globalActor
final actor MyMainActor {
// Don’t allow others to create instances
private init() {}
// Requirements from the implicit GlobalActor conformance
typealias ActorType = MyMainActor
static var shared: ActorType = MyMainActor()
static var sharedUnownedExecutor: UnownedSerialExecutor {
mainExecutor.asUnownedSerialExecutor()
}
// Requirement from the implicit Actor conformance
nonisolated var unownedExecutor: UnownedSerialExecutor {
mainExecutor.asUnownedSerialExecutor()
}
}
// Store main executor in a global to keep it alive
private let mainExecutor = MainExecutor()
final class MainExecutor: SerialExecutor {
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)
}
func enqueue(_ job: UnownedJob) {
DispatchQueue.main.async {
job._runSynchronously(on: self.asUnownedSerialExecutor())
}
}
}
// MARK: - Usage example
import Foundation
actor SomeActor {
func f() async {
assert(!Thread.isMainThread)
await mainA()
assert(!Thread.isMainThread)
}
}
@MyMainActor
func mainA() {
assert(Thread.isMainThread)
}
@main struct Main {
static func main() async {
await SomeActor().f()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment