AwaitKit
AwaitKit copied to clipboard
Return to main thread
Hello!
Maybe this is a stupid question but I haven't been able to solve it as of yet.
I have something like
async {
let report = try await(self.reportStore.getReport())
//update UI
}
As I am inside the async I am not in the main thread and get whacky behaviour on the UI. But if I call the await in the main thread I get a deadlock on the semaphore wait. what should I do if I want to get back to the main thread with my result?
Thanks
Yes indeed, this is a bit annoying. For the moment the workaround is to use the DispatchQueue.main.async
method.
I was trying to think of a work-around for being able to call await from the main thread without locking a semaphore.
This is what I came up with:
extension DispatchQueue {
@discardableResult
public func awaitOnMainQueue<T>(_ promise: Promise<T>, interval: TimeInterval = 0.1) throws -> T {
/// Checking for main thread does NOT really guarantee the main queue, but what else can we do?
guard Thread.isMainThread else {
throw NSError(domain: "com.yannickloriot.awaitkit", code: 0, userInfo: [
NSLocalizedDescriptionKey: "Operation was aborted.",
NSLocalizedFailureReasonErrorKey: "This method can only be run on the main queue."
])
}
var result: T?
var error: Swift.Error?
var completed: Bool = false
promise
.then(on: self) { value -> Promise<Void> in
result = value
completed = true
return Promise()
}
.catch(on: self, policy: .allErrors) { err in
error = err
completed = true
}
while !completed {
RunLoop.current.run(until: NSDate().addingTimeInterval(interval) as Date)
}
guard let unwrappedResult = result else {
throw error!
}
return unwrappedResult
}
}
public func awaitOnMainQueue<T>(_ promise: Promise<T>, interval: TimeInterval = 0.1) throws -> T {
return try DispatchQueue.main.awaitOnMainQueue(promise, interval: interval)
}
The reason I needed this is that many network APIs dispatch their results back to the main queue.
@flockoffiles But why does your solution result in a deadlock when calling mainQueueAwait()
inside a DispatchQueue()
? I have a Dispatch Group with a notify()
method and when I call mainQueueAwait()
inside, it deadlocks.
you can put your UI updating code in a done { } block after async because async will return Promise<Void>
. The done block is automatically called on the main thread.