swiftfirebasedispatch-async

Swift: Waiting for dispatch_async to finish on main thread


I feel like there is an obvious solution to this that is on the tip of my brain, but I can't seem to figure it out. I am using the FirebaseAuth library, so I can't edit it (or I don't want to go down that path). The function getIDTokenForcingRefresh() uses dispatch_async. This would be a lot easier if it used the async/await functionality from Swift 5.5, but I have to rely on solutions for dispatch_async. I need to grab the output to run a Firebase function request using the token. The following obviously doesn't work because the function will return before getIDTokenForcingRefresh() is finished. I don't care if the main thread is blocked because the user can't proceed in the app until this is done.

    var userToken: String {

        print("FIREBASE: Getting User Token")
        var token = ""
        Auth.auth().currentUser?.getIDTokenForcingRefresh(true) { idToken, error in
            if let error = error {
                print("FIREBASE: There was an error getting the user token")
                return
            }
            print("FIREBASE: Got user token: \(idToken ?? "NONE")")
            token = idToken ?? ""
        }
        print("FIREBASE: Token: \(token)")
        return token
    }

Solution

  • Even with a completion handler method like getIDTokenForcingRefresh you can take advantage of async/await by wrapping the asynchronous function with completion handler in a Continuation. The error handling is for free

    func getUserToken() async throws -> String {
        print("FIREBASE: Getting User Token")
        return withCheckedThrowingContinuation { continuation in
            Auth.auth().currentUser?.getIDTokenForcingRefresh(true) { idToken, error in
                if let error {
                    print("FIREBASE: There was an error getting the user token: \(error.localizedDescription)")
                    continuation.resume(throwing: error)
                } else {
                    print("FIREBASE: Got user token: \(idToken ?? "NONE")")
                    continuation.resume(returning: idToken!)
                }
            }
        }
    }
    

    And use it

    Task {
        do {
            let token = try await getUserToken()
        } catch {
            print(error)
        }
    }
    

    Doesn't Firebase support async/await meanwhile?