Hello,
I have such code, that is converting async/ await code to completion-based code (for backwards compatibility purposes).
final class Repository {
func fetchData() async throws -> Data {
// simulate network call
try await Task.sleep(for: .seconds(1))
return Data()
}
func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
Task {
let result: Result<Data, Error>
do {
result = try await .success(fetchData())
} catch {
result = .failure(error)
}
Task.detached { @MainActor in
// completion needs to run on the main thread
// completion needs to be destroyed on the main thread
completion(result)
}
}
}
}
The completion needs to run & be destroyed on the main thread, so there are 3 different alternatives (at least?) to achieve this
Task { @MainActor inTask.detached { @MainActor inDispatchQueue.main.async {
I don’t really know what are the differences between these options, in this context, and therefore which one to choose. They all seem to be doing the same thing, which is executing some block of code on the main thread. But in case there are any differences between the 3 approaches, I would like to choose the one that suits best my case.
There is also a fourth option, that works, but it introduces an unwanted side-effect.
Annotating the Task with @MainActor, i.e
Task { @MainActor in
let result: Result<Data, Error>
do {
result = try await .success(fetchData())
} catch {
result = .failure(error)
}
completion(result)
}
This option introduces a slight delay in the execution of the task, as the block needs to be enqueued on the main thread, and then once it starts executing, it will immediately leave the main thread, due to try await fetchData().