首页 > 解决方案 > DispatchGroup 只会在方法被调用两次时退出

问题描述

我正在尝试使用 Firebase 身份验证注册用户。当用户注册时,我希望将它们添加到我Users在 Firestore 中的收藏以及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)
    }
}

用户助手.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)
        }
    }
}

用户数据模型.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)
        }
    }
}

任何帮助是极大的赞赏!谢谢大家

标签: iosswiftfirebaseasynchronousclosures

解决方案


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

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

  2. 不违反关于在没有授权 uid 的情况下写入数据库的 Firestore 规则

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

推荐阅读