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