Is there a way to execute code on the main thread inside a Task?

I'm working on a GUI app, so inside a Task I want to update the UI, which is only possible from the main thread.
There is the old GCD way of doing it, with libdispatch's DispatchQueue, but I was wondering if there's a more modern way of doing it with a Task

Task.detached(priority: .background) {
     let result = await doSomeHeavyAsyncTask()
    // this now needs to be done on the main thread 
   myWidget.update(result)
}

I think it would have been nice if we'd have a continuation like:

Task.detached(priority: .background) {
     let result = await doSomeHeavyAsyncTask()
    // this now needs to be done on the main thread 
   return result
}, continuationOnMain: { result in
      //this  runs on main thread
     myWidget.update(result)
}
await MainActor.run {
  ...
}

If you want to suspend while waiting for it to complete. (Documentation)

Alternatively:

Task.detached { @MainActor in
  ...
}

For a detached task on the main actor.

7 Likes

I think the "right" way to do this in Swift concurrency is to annotate the MyWidget.update method with @MainActor if at all possible. That way, the compiler can verify that the switch to the main actor happens and the caller can’t forget it.

2 Likes

Thanks Karl! This looks like exactly what I was looking for, since it's using actors, which are newer and should replace GCD and libdispatch.