I am currently trying to adapt concurrency into my existing codebase, where I am for instance using DispatchQueue.main to dispatch back to the main queue.
As far as I've understood we now should be able to use @MainActor to do nearly the same but with less boilerplate. Nevertheless I am currently stuck with the following problem:
When using the following code, the compiler complains that Converting function value of type '@MainActor () -> Void' to '@convention(block) () -> Void' loses global actor 'MainActor'. I assume thats because the DispatchQueue's block is not marked with @MainActor itself, but I thought with the code above the closure gets dispatched to main automatically. Did I get that wrong? Do I still have to use DispatchQueue.main?
In addition to that, if I try to run the above code, the doStuffOnMain() function isn't called on the main thread at all.
You can specify the queue where network request completion handler completes (via URLConfiguration). In most (all?) API's this queue specifying is possible one way or another (typically you pass the queue parameter, which is optional (if not specified the system picks some queue).
Back to your question, as a practical workaround I'd do smth like:
DispatchQueue.global().async {
// do something in background
Task {
await doStuffOnMain()
}
}
@MainActor func doStuffOnMain() { ... }
Or even good old DispatchQueue.main.async {...}
Actor and associated concurrency checks/errors are new but they are not yet "production ready" and are somewhat half-backed. A trivial example:
import Dispatch
class C {
@MainActor func doStuffOnMain() {}
func foo() {
DispatchQueue.main.async {
self.doStuffOnMain() // ok
}
}
func bar() {
let queue = DispatchQueue.main
queue.async {
self.doStuffOnMain()
// Error: error: call to main actor-isolated instance method 'doStuffOnMain()' in a synchronous nonisolated context
}
}
func baz() {
typealias DispatchQueue = MySomethingElse
DispatchQueue.main.async { // this is not what it looks
self.doStuffOnMain() // ok
}
}
}
struct MySomethingElse {
static var main: DispatchQueue { DispatchQueue.global() }
}
Here foo and bar are obviously doing the same thing, yet one compiles and another doesn't. And 'baz' compiles fine, but shouldn't. The checks are shallow and not robust yet.