从Firebase更新数组值后TableView未刷新,如何解决?
如何从Firebase更新TableView数据源并刷新界面?
问题描述
我有一个静态TableView,它的数据源是这个数组:
var profiles = [ Profile(title: "Email", description: "Add Email"), Profile(title: "Gender", description: "Add Gender"), Profile(title: "Location", description: "Add Location"), Profile(title: "About", description: "Add About") ]
我通过Firebase数据库获取数据,尝试更新数组里元素的description字段,但更新后界面没有显示新内容。我的代码如下:
fileprivate func updateUserProfile() { guard let uid = Auth.auth().currentUser?.uid else { return } Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in guard let value = snapshot.value as? [String: Any] else { return } guard let emailDescription = value["email"] as? String else { return } guard let genderDescription = value["gender"] as? String else { return} self.profiles[0].description = emailDescription self.profiles[1].description = genderDescription }) { (error) in print(error.localizedDescription) } }
解决方案
这是个很常见的UI刷新问题——你已经成功更新了数据源数组,但忘了告诉TableView「数据变了,该重新渲染了」!再加上Firebase回调线程的注意事项,问题就能解决,具体看下面:
更新数据源后手动触发TableView刷新
TableView不会自动监听数组的变化,必须调用tableView.reloadData()来通知它重新加载数据。确保UI操作在主线程执行
Firebase的observeSingleEvent回调是在后台线程触发的,所有UI相关操作(包括刷新TableView)都必须切换到主线程执行,否则会导致异常或不生效。
修改后的完整代码:
fileprivate func updateUserProfile() { guard let uid = Auth.auth().currentUser?.uid else { return } Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in guard let value = snapshot.value as? [String: Any] else { return } guard let emailDescription = value["email"] as? String else { return } guard let genderDescription = value["gender"] as? String else { return} // 更新数据源 self.profiles[0].description = emailDescription self.profiles[1].description = genderDescription // 切回主线程刷新TableView DispatchQueue.main.async { self.tableView.reloadData() } }) { (error) in print(error.localizedDescription) } }
额外优化建议
目前你用硬索引(self.profiles[0]、self.profiles[1])来更新元素,如果后续数组顺序变化,代码就会出错。建议通过匹配title字段来更新,让代码更健壮:
// 替换原来的硬索引更新逻辑 for index in 0..<self.profiles.count { switch self.profiles[index].title { case "Email": self.profiles[index].description = emailDescription case "Gender": self.profiles[index].description = genderDescription // 可以继续添加其他字段的匹配逻辑 default: break } }
内容的提问来源于stack exchange,提问作者ferryawijayanto
相关产品推荐
相关产品推荐

