Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return to main thread #26

Open
Mijail opened this issue Mar 1, 2018 · 4 comments
Open

Return to main thread #26

Mijail opened this issue Mar 1, 2018 · 4 comments

Comments

@Mijail
Copy link
Contributor

Mijail commented Mar 1, 2018

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

@yannickl
Copy link
Owner

yannickl commented Mar 3, 2018

Yes indeed, this is a bit annoying. For the moment the workaround is to use the DispatchQueue.main.async method.

@flockoffiles
Copy link

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.

@teodorciuraru
Copy link

teodorciuraru commented Aug 1, 2018

@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.

@djtech42
Copy link
Contributor

djtech42 commented Feb 25, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants