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

