Reputation: 3462
I'm using the native ASWebAuthenticationSession to do a web-view based authentication and I 'm getting this runtime warning with corresponding console output:
Main Thread Checker: UI API called on a background thread: -[UIWindow init] PID: 15042, TID: 2317190, Thread name: (none), Queue name: com.apple.root.user-initiated-qos.cooperative, QoS: 25
So I have added the @MainActor attribute to the method but it has no effect. still getting the same warning and same console output:
Main Thread Checker: UI API called on a background thread: -[UIWindow init] PID: 15476, TID: 2328029, Thread name: (none), Queue name: com.apple.root.user-initiated-qos.cooperative, QoS: 25
Am I missing something? where I can find
Upvotes: 3
Views: 1827
Reputation: 3497
Synchronous methods run on the same thread as the caller regardless of any actor annotations. E.g:
func foo() {
// this will run on whichever thread it's called from
}
@MainActor
func foo2() {
// this will ignore @MainActor and also run on the same thread it's called from.
// if the caller is the main thread, it will run on the main thread.
// if the caller is a background thread, it will run on the background thread.
}
When I first started learning about actors I thought foo2
would be guaranteed to run on the main thread given it's annotated with @MainActor
and the main actor's executor uses the main thread. What I didn't realise was that this only happens if the method is async
. E.g.:
@MainActor
func foo3() async {
// This is guaranteed to run on the main thread regardless of the caller's thread
}
Because foo3
is marked as async
, the call site's Task
can suspend execution and give up its thread. This allows foo3
to 'hop' onto a different actor if needed. In this example, foo3
is explicitly annotated with @MainActor
so it inherits that context.
Even if we used a method that wasn't annotated explicitly, it might still implicitly inherit an actor context. E.g.
@MainActor
class Bar {
func foo4() async {
// this implicitly inherits the actor context from `Bar`
}
}
So foo4
above would be isolated to the main actor and run on the main thread. But, if we removed async
then it would run on the same thread as the caller and essentially ignore Bar
's @MainActor
annotation.
If an async
method isn't isolated to an actor, it will run on the default executor, which uses a pool of background threads. This means that it can run on a different thread even if it was called from the main thread. E.g.:
// inherits no actor context
func foo5() async {
// this will run on a background thread (even when called from the main thread)
}
So, to answer your question directly: the presentationAnchor(...)
method is ignoring the @MainActor
annotation because the method is synchronous. It will run on the same thread as the call site, which in this case is a background thread.
To isolate it to the main actor and use the main thread, you could either:
i) keep the @MainActor
annotation and mark the method with async
. Or, if you can't modify the call site,
ii) manually place the code within the method on the main actor e.g. Task { @MainActor ... }
.
Upvotes: 6