DispatchQueue.main.async code block not getting executed.

I am working on a bundle project in swift for MacOS which is used as an authorization plugin which runs at login (https://developer.apple.com/documentation/security/authorization_plug-ins/using_authorization_plug-ins) and in the bundle project I am doing API request call using URLSession.shared.dataTask and in the call back I receive, I am trying to update the UI and as updating UI has to be done using main thread I am using DispatchQueue.main.async and the code inside DispatchQueue.main.async is never getting executed! This works perfectly fine in a normal macOS Cocoa application but the problem persists with Bundle project for macOS.



CODE:


class MainForm: NSWindowController{
   
    public var bodyParams: [String: Any]?
   
    override func windowDidLoad() {
        super.windowDidLoad()
        testfetch{ (Response) in
            os_log("In completion handler response: %@", Response)
           //code to update some UI follows
        }
    }
   
    func testfetch(completion: @escaping (Response) -> ()){
        os_log("Is this mainthread in testFetch %@", Thread.isMainThread ? "Yes" : "No")
        os_log("Current thread testFetch %@", Thread.current)
        let url = URL(string: "https://example.com")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        bodyParams = ["username": "******", "password": "*****"]
        if let bodyParams = bodyParams {
            guard let body = try? JSONSerialization.data(withJSONObject: bodyParams, options: []) else {
                return
            }
            request.httpBody = body
            let task = URLSession.shared.dataTask(with: request) {(data, response, error) in
                guard let data = data else {
                    os_log("Data not recieved!!")
                    return
                }
                os_log("Is this mainthread in dataTask %@", Thread.isMainThread ? "Yes" : "No")
                os_log("Current thread in dataTask %@", Thread.current)
                os_log("Data recieved in testFetch: %@", String(data: data, encoding: .utf8)!)
                do{
                    let receivedData = try JSONDecoder().decode(Response.self, from: data)
                    DispatchQueue.main.async{
                        os_log("Is this mainthread in main.async %@", Thread.isMainThread ? "Yes" : "No")
                        os_log("Current thread in main.async %@", Thread.current)
                        completion(receivedData)
                    }
                }
                catch let Err{
                    os_log("Error is: %@", Err as! String)
                }
               
            }
            task.resume()
        }
    }
 
    struct Response: Codable {
        let name, age, status: String
    }
}

Logs:


  • Is this mainthread in testFetch? Yes
  • Current thread testFetch <NSThread: 0x7f9176001c30>{number = 1, name = main}
  • Is this mainthread in dataTask No
  • Current thread in dataTask <NSThread: 0x7f9173dc2080>{number = 4, name = (null)}
  • Data recieved in testFetch: {"name":"JohnDoe", "age": "**", "status": "single"}



So the logs in `DispatchQueue.main.async` and completion handler are never getting printed. I am quite new to swift and async programming any help would be much appreciated!

Replies

Authorisation plug-ins run in a very weird environment and problems like this are not super surprising. However, I ran a quick test here in my office and my async dispatch to main worked just fine. What OS release are you testing this on?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Well, that's weird cause I have been trying to resolve this issue for a while now, tried many approaches and none worked and when I comment out DispatchQueue.main.async the completion handler is getting called but not on main thread but on thread opened by dataTask and as I am updating UI in completion handler this is causing issues! I am testing this on macOS Mojave (10.14.5), please let me know if you need more info, if needed I can mail you code samples!

I’m happy to dig deeper into your code, but I don’t have the time to do that in the context of DevForums. If you’re completely stuck, you open a DTS tech support incident and we can pick things up there.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Did open a code-level support ticket, waiting for a response thank you!

DTS has reviewed this issue and concluded that the Authorization Plugin windows was being run in modal event loop which is inherently synchronous by nature. All code that was queued to be run by GCD could not enter the modal run loop and therefore could not execute until modal runloop had completed. Using performSelector(onMainThread:with:waitUntilDone:) proved to be a workaround in this context.


As Quinn mentioned, Authorization plugins do not run in a normal environment so launching other processes or trying to combine complex logic into this environment is also not recommended. It's recommended to keep you GUI code as simplistic as possible to avoid edge cases that may crop up from not running in a full-fleged environment.


Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com