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

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数据

Firestore数据

界面效果(空白无数据)

FeedViewController界面


问题原因与修复方案

核心问题

从控制台输出能明确看到:reloadData()调用时,Firestore的异步请求还未完成,postArray仍为空;等数据真正加载完成后,没有触发tableView.reloadData(),导致表格一直显示空白。

具体来说,getDataFromFirestore里的completion()是在添加快照监听器后立即执行的,而非快照回调完成后——这直接导致viewDidLoad里的reloadData()在数据未加载时就调用,完全起不到作用。

修复步骤

  1. 调整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()
}
  1. 可选优化:移除viewDidAppear里的reloadData(),因为快照监听器会实时监听数据变化,保留该行可能导致不必要的刷新;若需确保页面每次出现时刷新,可保留,但建议依赖Firestore的实时监听机制。
  2. 线程安全保障:显式确保UI操作在主线程执行(Firestore快照回调默认在主线程,但显式标注更稳妥):
    在completion中调用reloadData时,包裹主线程代码:
DispatchQueue.main.async {
    self.tableView.reloadData()
}

额外注意事项

  • 使用addSnapshotListener会实时监听Firestore集合的变化,每次数据更新都会触发回调,因此每次回调时需先清空postArray,避免重复添加数据。
  • 避免滥用强制类型转换as!,尽量使用as?并做安全处理,你的代码中已经实现了这一点,保持即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:17:07