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

用户名查重逻辑异常:误报已占用却成功修改问题排查求助

问题分析与修复方案

首先,咱们来揪出这个诡异矛盾问题的根源:你在updateUsername()里用了query.observe(.value)来查询用户名是否存在——这个方法是持续监听该节点数据变化的!

具体的错误流程是这样的:

  1. 输入一个未被占用的用户名,点击完成
  2. 第一次查询执行,DataSnapshot.exists()返回false,于是你把新用户名写入数据库
  3. 数据库里新增了这个用户名后,observe(.value)的监听回调被再次触发
  4. 这次DataSnapshot.exists()变成true,所以弹出了「用户名已被占用」的错误横幅
  5. 但第一次回调已经执行了数据库修改和控制台打印,就出现了你看到的“成功修改却弹出错误”的矛盾现象

核心修复步骤

把持续监听改成单次查询,用observeSingleEvent(of: .value)替换observe(.value),这样只会查询一次,不会因为后续数据库更新再次触发回调。

另外还有几个小细节可以优化:

  • textFieldDidEndEditing里trimmedString已经做了lowercased(),后面updatedUsername = trimmedString?.lowercased()是重复操作,可以删掉重复的lowercased()
  • 弹出错误横幅后,要确保不会执行关闭视图的逻辑,避免用户被卡在当前页面

修正后的代码

func textFieldDidEndEditing(_ textField: UITextField) {
    let trimmedString = usernameTextField.text?.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression).lowercased()
    guard let validUsername = trimmedString, validUsername != "" else {
        print("ERROR: Please enter a valid username")
        usernameChanged = false
        return
    }
    updatedUsername = validUsername
    usernameChanged = true
}

func updateUsername() {
    guard let updatedUsername = self.updatedUsername else { return }
    guard let currentUid = Auth.auth().currentUser?.uid else { return }
    guard usernameChanged == true else { return }
    
    let reference = Database.database().reference().child("activeUsernames")
    let query = reference.queryOrdered(byChild: "username").queryEqual(toValue: updatedUsername )
    
    // 替换成单次查询,避免因数据库更新重复触发回调
    query.observeSingleEvent(of: .value, with: { (dataSnapshot) in
        if dataSnapshot.exists() {
            print("Username already exists")
            self.errorBanner()
        } else {
            print("Username successfully changed")
            // 先更新activeUsernames节点
            reference.child(currentUid).child("username").setValue(updatedUsername)
            // 再更新用户信息节点
            USER_REF.child(currentUid).child("username").setValue(updatedUsername) { (err, ref) in
                if let err = err {
                    print("Failed to update username: \(err.localizedDescription)")
                    return
                }
                // 更新成功后再刷新数据并关闭视图
                guard let userProfileController = self.userProfileController else { return }
                userProfileController.fetchCurrentUserData()
                self.navigationController?.popViewController(animated: true)
            }
        }
    })
}

@objc func handleDone() {
    view.endEditing(true)
    if usernameChanged {
        updateUsername()
    }
}

额外提示

  • 建议给errorBanner()方法添加交互逻辑,比如让用户可以手动关闭横幅,或者在弹出后自动聚焦用户名输入框,方便用户修改
  • 数据库操作最好加上完整的错误处理,比如setValue的回调里判断是否有错误,避免静默失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:50:11