简体   繁体   中英

DispatchGroup will only exit when method is called twice

I'm trying to sign up users with Firebase auth. When a user signs up, I'd like them to be added to my Users collection in Firestore as well as the Users authorization section.

The createUser(withEmail: ...) method works every time. However, my db.collection("users").document(user.id).setData([..] method will only be called if I press the sign up button twice, and at that point the createUser(withEmail ...) method gets called again. Here's the relevant code

SignupViewController.swift

@IBAction func signupButtonTapped(_ sender: UIButton) {
    // user: User() defined here

    usersHelper.signup(user: user, password: password) { result in
        // This closure is only executed on the second press
        guard let user = result as? Firebase.User else {
            let error = result as? Error
            self.handleSignupError(error!)
            return
        }
        self.performSegue(withIdentifier: "ShowGroupsFromSignupSegue", sender: self)
    }
}

UsersHelper.Swift

func signup(user: User, password: String, completion: @escaping (_ result: Any?) -> Void) {
    let userDispatchGroup = DispatchGroup()
    var signupError: Error? = nil
    var dbError: Error? = nil
    var firebaseUser: Firebase.User? = nil

    userDispatchGroup.enter()
    usersDataModel.signupUser(user: user, password: password) { result in
        // Completion handler
        if result as? Error != nil {
            signupError = result as? Error
        } else {
            // Got the user
            firebaseUser = result as? Firebase.User
        }
        userDispatchGroup.leave()
    }

    userDispatchGroup.enter()
    usersDataModel.create(user: user) { err in
        // This will only execute if signUp is called twice
        if let result = err as? Error {
            print("Error msg: \(result.localizedDescription)")
            dbError = result
        }
        print("!Created db user")
        userDispatchGroup.leave()
    }

    userDispatchGroup.notify(queue: .main) {
        print("!dispatch group completed successfully")
        if (signupError == nil && dbError == nil) {
            completion(firebaseUser)
        } else {
            signupError != nil ? completion(signupError) : completion(dbError)
        }
    }
}

UsersDataModel.swift

func signupUser(user: User, password: String, _ completion: @escaping (_ err: Any? ) -> Void) {
    // Create user in Auth & create DB entry
    Auth.auth().createUser(withEmail: user.email, password: password) { (authResult, err) in
        if let err = err {
            print("Error creating user \(err)")
            completion(err)
        } else {
            print("User signed up successfully")
            completion(authResult) // completion called with User
        }
    }
}


func create(user: User, _ completion: @escaping (_ result: Any?) -> Void) {
    // userData dictionary created here

    db.collection("users").document(user.ID).setData(userData) { err in
        if let err = err {
            print("There was an error creating the user \(err)")
            completion(err)
        } else {
            print("!User created in db successfully!")
            completion(nil)
        }
    }
}

Any help is greatly appreciated! Thank you all in advance

I've resolved the error. I ended up nesting the second network call in order to:

  1. Get the uid from the firestore who was authenticated

  2. Not break firestore rules about writing to the database w/o an authorized uid

My UsersHelper.swift file now looks like

func signup(user: User, password: String, completion: @escaping (_ result: Any?) -> Void) {
    let userDispatchGroup = DispatchGroup()
    var signupError: Error? = nil
    var dbError: Error? = nil
    var firebaseUser: Firebase.User? = nil

    userDispatchGroup.enter()
    usersDataModel.signupUser(user: user, password: password) { result in
        // Completion handler
        if result as? Error != nil {
            // there was an error?
            print("Error: \(result)")
            signupError = result as? Error
        } else {
            // Got the user
            firebaseUser = result as? Firebase.User
            // Create user entry in DB
            user.ID = firebaseUser!.uid

            self.usersDataModel.create(user: user) { err in
                // Completion handler
                if let err = err as? Error {
                    dbError = err
                }
                userDispatchGroup.leave()
                print("Done")
            }
        }
    }

    userDispatchGroup.notify(queue: .main) {
        print("!dispatch group completed successfully")
        if (signupError == nil && dbError == nil) {
            completion(firebaseUser)
        } else {
            signupError != nil ? completion(signupError) : completion(dbError)
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM