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

Swift如何从Firebase获取所有用户数据并解决属性随机报错问题

问题成因
  • User实例复用导致数据错乱:你将User()实例的创建逻辑写在了.observe(.childAdded)的异步回调外部,Firebase的childAdded事件会为每一个用户节点单独触发一次回调,所有回调都会修改同一个全局User实例的属性,且数组中追加的都是指向该实例的引用。异步回调的执行时序不可控,会出现前一次属性赋值未完成、后一次赋值就启动的情况,导致属性值错乱,随机触发KVC匹配错误。
  • Swift属性未对Objective-C runtime可见:你使用的setValuesForKeys(_:)是Objective-C的KVC接口,Swift 4及以上版本默认不会自动将Swift属性暴露给ObjC runtime,KVC无法识别你定义的email、first_name等属性,会触发未定义键的崩溃。
解决方法

需要同时修改User类定义和数据获取逻辑,具体修改如下:

  1. 修正User类的属性修饰,让KVC可以识别属性,两种方案二选一即可:
// 方案1:逐个给属性添加@objc修饰
public class User : NSObject{
  @objc var email: String?
  @objc var first_name: String?
  @objc var last_name: String?
  @objc var profile_picture: String?
}

// 方案2:给整个类添加@objcMembers修饰,批量暴露所有属性给ObjC runtime
@objcMembers public class User : NSObject{
  var email: String?
  var first_name: String?
  var last_name: String?
  var profile_picture: String?
}
  1. 将User实例的创建逻辑挪到回调闭包内部,每次回调都生成全新的实例,避免复用:
var users = [User]()

func fetchUserData () {
   Database.database().reference().child("users").observe(.childAdded, with: { snapshot in
     if let dictionary = snapshot.value as? [String: AnyObject] {
        // 每次触发回调都生成新的User实例
        let user = User()
        user.setValuesForKeys(dictionary)
        self.users.append(user)
    }
  }, withCancel: nil)
}

优化建议(可选)

如果不想依赖KVC的自动赋值,可以改用手动赋值的方式,容错性更高,就算数据库字段和类属性不匹配也不会触发崩溃:

if let dictionary = snapshot.value as? [String: AnyObject] {
    let user = User()
    user.email = dictionary["email"] as? String
    user.first_name = dictionary["first_name"] as? String
    user.last_name = dictionary["last_name"] as? String
    user.profile_picture = dictionary["profile_picture"] as? String
    self.users.append(user)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 11:39:03