You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DispatchGroup需两次调用才退出:Firebase注册后Firestore写入异常

问题分析与解决方案

看起来你遇到的核心问题是Firestore文档创建依赖的用户ID还未生成,就并行执行了Auth注册和Firestore写入操作,导致第一次点击时Firestore写入失败,第二次点击时因为之前的Auth注册已经完成、用户ID已存在,才成功执行写入。同时你的代码还存在类型转换错误,导致回调逻辑异常。

问题根源拆解

  1. 并行任务的依赖错误:你用DispatchGroup同时启动了Auth注册和Firestore写入,但Firestore写入需要Auth生成的用户ID,这两个任务是串行依赖关系,不能并行执行。第一次点击时,user.ID还是初始值(大概率是空字符串),导致Firestore的document(user.ID)无效,写入操作失败或无效果。
  2. 类型转换错误:signupUser方法返回的是AuthDataResult类型,你却尝试把它直接转成Firebase.User,导致第一次回调时firebaseUser为nil,触发错误分支,而你误以为是Firestore写入没执行。
  3. 重复点击未限制:注册按钮没做防重复点击处理,导致第二次点击时重复调用了Auth注册接口。

具体修复步骤

1. 修正Auth注册方法,返回正确的用户对象

在UsersDataModel.swift中,修改signupUser方法,确保返回的是Firebase.User类型:

func signupUser(user: User, password: String, _ completion: @escaping (_ result: Any?) -> Void) {
    Auth.auth().createUser(withEmail: user.email, password: password) { (authResult, err) in
        if let err = err {
            print("Error creating user \(err)")
            completion(err)
        } else {
            guard let firebaseUser = authResult?.user else {
                let error = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to retrieve user from auth result"])
                completion(error)
                return
            }
            print("User signed up successfully")
            completion(firebaseUser) // 现在返回的是正确的Firebase.User对象
        }
    }
}

2. 改为串行执行任务,确保用户ID存在后再写入Firestore

在UsersHelper.swift中,去掉不必要的DispatchGroup,改为串行执行Auth注册和Firestore写入:

func signup(user: User, password: String, completion: @escaping (_ result: Any?) -> Void) {
    // 先完成Auth注册
    usersDataModel.signupUser(user: user, password: password) { result in
        if let signupError = result as? Error {
            completion(signupError)
            return
        }
        
        // 拿到Auth生成的用户对象
        guard let firebaseUser = result as? Firebase.User else {
            let error = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid user data returned"])
            completion(error)
            return
        }
        
        // 将Auth生成的UID赋值给本地User模型
        var updatedUser = user
        updatedUser.ID = firebaseUser.uid
        
        // 现在再执行Firestore写入
        usersDataModel.create(user: updatedUser) { dbResult in
            if let dbError = dbResult as? Error {
                completion(dbError)
                return
            }
            
            // 两个操作都成功,返回Firebase用户对象
            completion(firebaseUser)
        }
    }
}

3. 给注册按钮添加防重复点击限制

在SignupViewController.swift的signupButtonTapped方法中,添加按钮状态控制:

@IBAction func signupButtonTapped(_ sender: UIButton) {
    // 点击后立即禁用按钮,防止重复触发
    sender.isEnabled = false
    
    // 你的user和password获取逻辑...
    let user = User() // 替换成你实际的用户对象初始化逻辑
    guard let password = passwordTextField.text else {
        sender.isEnabled = true
        return
    }
    
    usersHelper.signup(user: user, password: password) { result in
        defer {
            // 无论成功失败,都重新启用按钮
            sender.isEnabled = true
        }
        
        guard let user = result as? Firebase.User else {
            let error = result as? Error
            self.handleSignupError(error!)
            return
        }
        
        self.performSegue(withIdentifier: "ShowGroupsFromSignupSegue", sender: self)
    }
}

额外检查点

确保UsersDataModel.swift的create方法中,userData字典包含正确的字段,且使用user.ID作为文档ID:

func create(user: User, _ completion: @escaping (_ result: Any?) -> Void) {
    let userData: [String: Any] = [
        "id": user.ID,
        "email": user.email,
        // 添加其他需要存储的用户字段
    ]
    
    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)
        }
    }
}

内容的提问来源于stack exchange,提问作者N0ug4t

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:23:07