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

Swift 3中setValuesForKeys字典报错:Firebase取userId加载tableView遇SIGABRT

解决setValuesForKeys引发的SIGABRT崩溃问题

嘿,我看到你在从Firebase获取数据并展示到TableView时遇到了崩溃问题,错误出在user.setValuesForKeys(dictionary)这一行。这其实是NSKeyValueCoding(KVC)机制的典型坑,我来帮你理清原因和解决办法:

崩溃原因

setValuesForKeys(_:)是KVC的核心方法,它会遍历传入字典的所有键,尝试给你的User对象对应的属性赋值。但如果你的User类没有定义字典中存在的某个键对应的属性,同时又没有实现setValue(_:forUndefinedKey:)方法来处理这些“未定义键”,KVC就会直接抛出NSUndefinedKeyException,触发SIGABRT崩溃。

从你的代码来看,Firebase的locations节点下很可能除了userId之外,还存在其他字段,而你的User类只定义了userId属性,这就导致了崩溃。

解决方案

这里有几种靠谱的解决方式,你可以根据需求选择:

1. 手动赋值(最安全推荐)

放弃KVC,直接从字典中取出对应的值赋值给User的属性,完全可控,不会因为额外字段崩溃:

func fetchUser() {
    Database.database().reference().child("locations").observe(.childAdded, with: {(snapshot) in
        if let dictionary = snapshot.value as? [String: Any] {
            let user = User()
            // 手动取出userId赋值
            user.userId = dictionary["userId"] as? String
            self.users.append(user)
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    } , withCancel: nil)
}

2. 实现setValue:forUndefinedKey:忽略未定义键

在你的User类中添加这个方法,让KVC遇到未定义键时直接忽略,而不是崩溃:

class User: NSObject {
    var userId: String?
    
    override func setValue(_ value: Any?, forUndefinedKey key: String) {
        // 什么都不做,忽略未定义的键
    }
}

3. 改用Swift Codable协议(现代Swift风格)

把User类改成遵循Codable协议,用JSONDecoder解析数据,同时设置忽略未知键,这样即使字典有额外字段也不会崩溃:

// 修改User类
class User: Codable {
    var userId: String?
}

// 修改fetchUser方法
func fetchUser() {
    Database.database().reference().child("locations").observe(.childAdded, with: {(snapshot) in
        if let dictionary = snapshot.value as? [String: Any] {
            do {
                let decoder = JSONDecoder()
                // 设置忽略未知键
                decoder.keyDecodingStrategy = .ignoreUnknownKeys
                let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
                let user = try decoder.decode(User.self, from: data)
                self.users.append(user)
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            } catch {
                print("解析用户数据失败:\(error)")
            }
        }
    } , withCancel: nil)
}

额外注意:TableView的小问题

你的代码里还有一个容易导致表格不显示内容的问题:numberOfSections(in:)返回了users.count,这意味着每个用户会成为一个单独的section,而你没有实现numberOfRowsInSection方法,默认每个section只有0行,所以表格会是空的。正确的写法应该是:

override func numberOfSections(in tableView: UITableView) -> Int {
    // 只需要一个section
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // 行数等于用户数量
    return users.count
}

这样修改后,你的TableView就能正常显示用户ID了。

内容的提问来源于stack exchange,提问作者burak nurçişek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:50:40