Library callbacks and actor isolation

If I'm in a callback function that is called by library code, and I need to return a value from a MainActor-isolated property, how can I get at it?

As a callback, I basically have no guarantees about what thread it will get called on. If I know I'm not on the main thread, I can do DispatchQueue.main.sync { ··· } and the compiler is happy.

But if I verify that I'm running on the main thread, how do I convince the compiler that I'm in the MainActor's context and can safely access isolated stuff?

I can't fire off a task with e.g. Task { @MainActor in ··· } because I have to wait for the task to finish and get me a result, and since I'm already on the main thread where that task would run, that's deadlock.

2 Likes

I’d like to clarify your requirements here. Can you post some snippets of code that illustrate the issue?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

My specific case is that I'm working with libgit2, where I have things like git_remote_callbacks.git_indexer_progress_cb in which I can return a negative value to cancel.

If sorry but I’m not familiar with that library. I was hoping to get a model of the problem, something that abstracts away the specific library details but is concrete enough to discuss the mechanics.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

I had this problem too. Here's what fell out of a previous discussions I had when trying to deal with this:

func unsafelyRunOnMainActor<T>(_ work: @MainActor () throws -> T) rethrows -> T {
	return try _unsafelyRunOnMainActor(work)
}

@MainActor(unsafe)
func _unsafelyRunOnMainActor<T>(_ work: @MainActor () throws -> T) rethrows -> T {
	try work()
}

This roundabout technique lets you (unsafely) tell Swift that you're on the MainActor already and would like to run code on it. (The specific context I needed this was a pre-concurrency protocol that I knew was @MainActor but not annotated as such, so I had to conform to it with nonisolated methods.)

2 Likes

As I understand it (from this post; I can't find any official docs), @MainActor(unsafe) is a transitionary thing that will do nothing in Swift 6.

1 Like