Search code examples
swiftcompletionhandlerdispatchgroup

Swift - Why is DispatchGroup not working in this function?


I am waiting for idToken response before returning the variable.

Please don't tell me to just use completion handler and call it without a DispatchGroup. I know I can do that, but I am trying to understand why this logic does not work.

func createToken() -> String {
    
    var token = "empty"
    var group = DispatchGroup()
    group.enter()
    
    let currentUser = Auth.auth().currentUser
    
    currentUser?.getIDTokenForcingRefresh(true) { idToken, error in
        
        token = idToken ?? "error"
        print("Token Set")
        group.leave()
    }
    
    group.wait(timeout: DispatchTime.now() + 10)

    return token
}

Running:

print("create ")
print(createToken())
print("done")

Output:

create 
empty
done
Token Set

Solution

  • If getIDTokenForcingRefresh dispatches its completion handler closure back to the main queue, you would see precisely the behavior you describe. When execution hits the wait call, it will block the main thread. But if the completion handler closure is being dispatched to the main queue, that will not be able to run until the wait call times out and the main thread is freed again.

    You can confirm this thesis, that getIDTokenForcingRefresh is calling its completion handler on the main thread, in a variety of ways:

    • Try removing the timeout, in which case this code would completely deadlock if it was using the main queue/thread.

    • Print Thread.isMainThread.

    • Add a precondition statement:

      dispatchPrecondition(condition: .onQueue(.main))
      
    • Set a breakpoint in this closure and let the debugger tell you which thread was used.

    But you are quite right: The wait pattern should be avoided in general.