Swift中Firebase数据库用户存在性校验失效问题排查
问题描述
我希望在邮箱已注册时阻止账号创建,为此编写了Swift代码,但无论邮箱是否已存在,控制台始终输出“doesnt exist”。我怀疑是否因为账号创建操作在第二个视图控制器中,与校验不同步导致的?
数据库校验代码
final class DatabaseManager { static let shared = DatabaseManager() private let database = Database.database().reference() } // MARK: - Account Management extension DatabaseManager { public func userExists(with email: String, completion: @escaping ((Bool) -> Void)) { var safeEmail = email.replacingOccurrences(of: ".", with: "-") safeEmail = safeEmail.replacingOccurrences(of: "@", with: "-") database.child(safeEmail).observeSingleEvent(of: .value, with: { snapshot in guard snapshot.value as? String != nil else { completion(false) return } completion(true) }) } }
调用代码
//FireBase Log In DatabaseManager.shared.userExists(with: email, completion: { [weak self] exists in guard let strongSelf = self else { return } guard !exists else { strongSelf.alertInvalidEmail() print("already exists") return } print("doesnt exist") self?.presenter(vc, animated: false, pushing: true, completion: nil) // success, present next vc })
排查与解决方案
- 数据库节点匹配问题:先去Firebase控制台检查数据库中存储的用户节点名称,是否和你生成的
safeEmail格式一致。比如邮箱test@example.com处理后是test-example-com,要确认数据库里是否存在这个节点。另外注意邮箱大小写,建议处理前统一转成小写(email.lowercased()),避免大小写差异导致匹配失败。 - 快照判断逻辑错误:你当前用
snapshot.value as? String != nil判断用户是否存在,但如果用户节点下存储的是字典(比如包含用户名、手机号等信息),snapshot.value会是[String: Any]类型,转成String必然为nil,所以永远返回false。正确的做法是直接使用snapshot.exists()方法,它会直接检查节点是否存在,和节点内的数据类型无关。修改后的校验方法代码:
public func userExists(with email: String, completion: @escaping ((Bool) -> Void)) { var safeEmail = email.lowercased().replacingOccurrences(of: ".", with: "-") safeEmail = safeEmail.replacingOccurrences(of: "@", with: "-") database.child(safeEmail).observeSingleEvent(of: .value, with: { snapshot in completion(snapshot.exists()) }) }
- 异步同步问题:你的调用逻辑没问题,
observeSingleEvent是异步回调,后续的页面跳转和提示都在回调内执行,不会出现同步问题。如果回调根本没触发,要检查Firebase数据库的读取权限是否开启(开发阶段可临时设置规则为.read = true测试),同时确认Firebase配置文件是否正确集成到项目中。
内容的提问来源于stack exchange,提问作者user19534819
相关产品推荐
相关产品推荐

