Actors and sync system callbacks (e.g. app delegate)

I am currently in the process of converting one of the singletons in my app, a class which manages a specific global state, to an actor, specifically a global actor. For the sake of this question, let's say that this global actor manages the user's state, and answers questions like "Is the user signed in?".

This change has been pretty smooth sailing so far, up until the point where I need to call my actor in a synchronous system method that expects a return value. These are pretty common in the App Delegate for example i.e. UIApplication's application(_:open:options:) or application(_:continue:restorationHandler:), both of which expect a Boolean return value.

In this example, I might need to first call something like await isUserSignedIn in order to access my actor. This isUserSignedIn method might not do any heavy lifting, and in fact, before it was an actor, it just ran on the main thread as normal. However, now that it is an actor, it must be called asynchronously.

Of course, those system callbacks are not async (understandably).

What is the best way to deal with this situation? It would be a shame if I had to explicitly block the main thread using something like a semaphore (even though that is essentially what isUserSignedIn already did, before it was an actor).

Thoughts?

Accepted Reply

What is the best way to deal with this situation?

There isn’t a good solution to this.

It would be a shame if I had to explicitly block the main thread using something like a semaphore (even though that is essentially what isUserSignedIn already did, before it was an actor).

That’s one of the less-than-good solutions.

Another is for your actor to mirror the state needed by this app delegate callback to something that’s bound to the main actor. That way the app delegate will be able to access it directly. The main drawback with that approach is that there are now two copies of the data, which raises the possibility of race conditions. However, it sounds like that’s unavoidable anyway.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

What is the best way to deal with this situation?

There isn’t a good solution to this.

It would be a shame if I had to explicitly block the main thread using something like a semaphore (even though that is essentially what isUserSignedIn already did, before it was an actor).

That’s one of the less-than-good solutions.

Another is for your actor to mirror the state needed by this app delegate callback to something that’s bound to the main actor. That way the app delegate will be able to access it directly. The main drawback with that approach is that there are now two copies of the data, which raises the possibility of race conditions. However, it sounds like that’s unavoidable anyway.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"