@MainActor does not always mean main thread
Seems to me some developers think that @MainActor means “always main thread” and has the same behaviour as DispatchQueue.main.async
which I don’t think is try. For example, the code below outputs:
before true
inside 1 false
after true
class Database {
func func1() async {
print("inside 1", Thread.isMainThread)
}
}
@main
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
let db = Database()
func applicationDidFinishLaunching(_ notification: Notification) {
Task {
print("before", Thread.isMainThread)
await db.func1()
print("after", Thread.isMainThread)
}
}
}
Because the Database class is not marked as @MainActor
then loadModel
will in fact be on a background thread, despite being invoked from an @MainActor
context. It seems what matters is where the func
is defined not the callsite. Sometimes class Database
is implemented as actor
Database
instead. Another way to await something executed on a background thread is to use nonisolated
, e.g.
@main
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
Task {
print("before", Thread.isMainThread)
await func1()
print("after", Thread.isMainThread)
}
}
nonisolated func func1() async {
print("inside 1", Thread.isMainThread)
}
}
The output is the same as the first example.