只有在调用两次方法时才会退出DispatchGroup

时间:2018-05-22 02:42:46

标签: ios swift firebase asynchronous closures

我尝试使用Firebase身份验证注册用户。用户注册后,我希望将其添加到Firestore中的Users集合以及Users授权部分。

createUser(withEmail: ...)方法每次都有效。但是,只有按两次注册按钮才会调用db.collection("users").document(user.id).setData([..]方法,此时会再次调用createUser(withEmail ...)方法。这是相关代码

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)
        }
    }
}

非常感谢任何帮助!提前谢谢大家

1 个答案:

答案 0 :(得分:0)

我已经解决了这个错误。我最终嵌套了第二个网络呼叫,以便:

  1. 从经过身份验证的firestore获取uid

  2. 不破坏关于使用授权的uid写入数据库的firestore规则

  3. 我的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 {
                // 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)
            }
        }
    }