Swift中UITableView无法显示Firebase Cloud Firestore获取的数据
UITableView未加载Firestore数据的问题排查与修复
我正在开发一个社交媒体Demo应用,但UITableView的表现不符合预期。完成数据获取操作后,UITableView并未展示获取到的内容。
FeedViewController代码
import UIKit import FirebaseFirestore class FeedViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! var postArray = [[String: Any]]() override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self getDataFromFirestore(){ print("self.tableView.reloadData() called from viewDidLoad()") self.tableView.reloadData() } } override func viewDidAppear(_ animated: Bool) { print("self.tableView.reloadData() called from viewDidAppear()") self.tableView.reloadData() } func getDataFromFirestore(completion: @escaping() -> Void){ let ref = Firestore.firestore().collection("posts") ref.addSnapshotListener { snapshot, error in if error != nil { self.makeAlert(title: "Error", message: error?.localizedDescription ?? "An error occoured during the process.") } else { if !(snapshot?.isEmpty ?? true) { for doc in snapshot!.documents { var dict = [String: Any]() dict["userID"] = doc.get("userID") as? String dict["comment"] = doc.get("comment") as? String dict["imageURL"] = doc.get("imageURL") as? String dict["likes"] = doc.get("likes") as? String self.postArray.append(dict) } } print("self.postArray.count been accessed from getDataFromFirestore(): \(self.postArray.count)") } } completion() } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FeedCell cell.lblUserEmail.text = self.postArray[indexPath.row]["userID"] as! String? ?? "" cell.lblLikes.text = self.postArray[indexPath.row]["likes"] as! String? ?? "" cell.lblUserComment.text = self.postArray[indexPath.row]["comment"] as! String? ?? "" return cell } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { print("self.postArray.count been accessed from numberOfRowsInSection: \(self.postArray.count)") return postArray.count } func makeAlert(title: String, message: String) { let controller = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert) let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.default) controller.addAction(action) self.present(controller, animated: true) } }
控制台输出
self.tableView.reloadData() called from viewDidLoad() self.postArray.count been accessed from numberOfRowsInSection: 0 self.postArray.count been accessed from numberOfRowsInSection: 0 self.postArray.count been accessed from numberOfRowsInSection: 0 self.tableView.reloadData() called from viewDidAppear() self.postArray.count been accessed from numberOfRowsInSection: 0 self.postArray.count been accessed from getDataFromFirestore(): 1
FeedCell代码
import UIKit class FeedCell: UITableViewCell { @IBOutlet weak var lblUserComment: UILabel! @IBOutlet weak var lblUserEmail: UILabel! @IBOutlet weak var imgView: UIImageView! @IBOutlet weak var lblLikes: UILabel! override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } @IBAction func btnLikeClicked(_ sender: Any) { } }
Firestore数据

界面效果(空白无数据)

问题原因与修复方案
核心问题
从控制台输出能明确看到:reloadData()调用时,Firestore的异步请求还未完成,postArray仍为空;等数据真正加载完成后,没有触发tableView.reloadData(),导致表格一直显示空白。
具体来说,getDataFromFirestore里的completion()是在添加快照监听器后立即执行的,而非快照回调完成后——这直接导致viewDidLoad里的reloadData()在数据未加载时就调用,完全起不到作用。
修复步骤
- 调整
getDataFromFirestore逻辑:将completion()移到快照回调内部,确保数据加载完成后再触发刷新:
func getDataFromFirestore(completion: @escaping() -> Void){ let ref = Firestore.firestore().collection("posts") ref.addSnapshotListener { snapshot, error in if error != nil { self.makeAlert(title: "Error", message: error?.localizedDescription ?? "An error occoured during the process.") completion() // 出错时也调用completion,避免逻辑阻塞 } else { self.postArray.removeAll() // 每次快照更新时清空旧数据,防止重复添加 if !(snapshot?.isEmpty ?? true) { for doc in snapshot!.documents { var dict = [String: Any]() dict["userID"] = doc.get("userID") as? String dict["comment"] = doc.get("comment") as? String dict["imageURL"] = doc.get("imageURL") as? String dict["likes"] = doc.get("likes") as? String self.postArray.append(dict) } } print("self.postArray.count been accessed from getDataFromFirestore(): \(self.postArray.count)") completion() // 数据加载完成后调用completion } } // 移除原来此处的completion() }
- 可选优化:移除
viewDidAppear里的reloadData(),因为快照监听器会实时监听数据变化,保留该行可能导致不必要的刷新;若需确保页面每次出现时刷新,可保留,但建议依赖Firestore的实时监听机制。 - 线程安全保障:显式确保UI操作在主线程执行(Firestore快照回调默认在主线程,但显式标注更稳妥):
在completion中调用reloadData时,包裹主线程代码:
DispatchQueue.main.async { self.tableView.reloadData() }
额外注意事项
- 使用
addSnapshotListener会实时监听Firestore集合的变化,每次数据更新都会触发回调,因此每次回调时需先清空postArray,避免重复添加数据。 - 避免滥用强制类型转换
as!,尽量使用as?并做安全处理,你的代码中已经实现了这一点,保持即可。
内容的提问来源于stack exchange,提问作者Seyit Gokce
相关产品推荐
相关产品推荐

