How to call an async function from a non-async function?

Assume I have a non-async function over which I have no control; e.g. NSBrowserDelegate
- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item

and the only way to get the required result is to call something async; e.g. item is an actor.


One way is to have the sync method block, e.g. waiting on a semaphore, and releasing this from the async context right after you got your result. I'm not sure if there is something more elegant.

BTW., you might want to rephrase the title of your question. I first thought you were just looking for a way to switch to an async context, whereas what you really want is to blockingly wait for an async context to finish.

In most cases the answer to this question is “Rethink your design.”

This isn’t new to Swift concurrency. You would see exactly the same problem if you were using Dispatch. The question you have to ask your self is: If this async function took 30 seconds to respond, what would my UI look like? And the answer to that is that you need a synchronous model layer that holds the current state of the UI and then you update that using async code (Swift concurrency, Dispatch, threads, whatever). That model layer, and hence your UI, needs a way to indicate to the user that you’re working on getting the latest info, like a spinner or a table row that says “Loading…”

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple


With that in mind, would you be so kind as to take a look at my problem Replace threadsafe var with new concurrency model (Actor?) of replacing a ThreadsafeVar with an Actor?

It seemed like a good idea, but the ThreadsafeVar is actually "unbalanced", in that the "getter" is synchronous but the "setter" is asynchronous - whereas an Actor is async in both directions.

Setting the var on the actor asynchronously is no problem - what I couldn't get to grips with was getting the value back.

Or should I stick with what I've got and understand that this is something that actors just aren't meant to be able to do?

Would love to see @eskimo insights on the matter.

Meanwhile, considering your specific refined question I wonder what pitfalls do you see in the proposed solution that shows how to avoid having the variable thread safe. Or is your question more open-ended, just the example could have been better?

Yes, that's the case. Plus, "thread safe var" can be also made "balanced" by having its setter synchronous as well (either with using a semaphore or a mutex, or (in some cases) with dispatch sync).

I thought I had explained this already.

Writing to the variable has to be done from a background thread, to avoid stalling the UI.

I am quite happy with the code as it is and I do not need to change my present way of working. I was simply asking for a clear explanation of whether replacing my present ThreadsafeVar with an Actor were feasible or not. If the answer is a definitive no, then I will stay with my present code.