Thursday, August 29, 2024

Calling async Code Synchronously in Swift

Wade Tregaskis:

I find my hand is often forced by APIs I don’t control (most often Apple’s APIs). e.g. data source or delegate callbacks that are synchronous and require you to return a value, but in order to obtain that value you have to run async code (perhaps because yet again that’s all you’re given by 3rd parties, or because that code makes sense to be async and is used happily as such in other places and you don’t want to have to duplicate it in perpetuity just to have a sync version).

If that asynchronosity is achieved through e.g. GCD or NSRunLoop or NSProcess or NSTask or NSThread or pthreads, it’s easy. There are numerous ways to synchronously wait on their tasks. In contrast, Swift Concurrency really doesn’t want you to do this. The language and standard library take an adamant idealogical position on this – one which is unfortunately impractical; a spherical chicken in a vacuum.

Nonetheless, despite Swift’s best efforts to prevent me, I believe I’ve come up with a way to do this.

[…]

Do not call this from a thread used by Swift Concurrency (e.g. an actor, including global actors like MainActor) if the closure - or anything it calls transitively via await - might be bound to that same isolation context. Doing so may result in deadlock.

Previously:

Comments RSS · Twitter · Mastodon

Leave a Comment