Table View无法显示从Firebase获取的数据问题求助
问题描述
尝试将Firebase数据显示到Table View时遇到困难,自认为代码逻辑正确,但数据始终无法正常显示。已尝试多日,求帮忙排查问题。
数据库结构截图


应用界面截图(Table View无数据)

相关代码
import UIKit import Firebase class InserisciViewController: UIViewController { @IBOutlet weak var labelTutorialInserisci: UILabel! @IBOutlet weak var buttonEntrate: UIButton! @IBOutlet weak var buttonUscite: UIButton! @IBOutlet weak var tableView: UITableView! var transactions: [Transaction] = [] let db = Firestore.firestore() let user = Auth.auth().currentUser // 定义交易结构体 struct Transaction { let userId: String let name: String let type: TransactionType let amount: Double let date: Date } // 定义交易类型枚举 enum TransactionType { case positive case negative } override func viewDidLoad() { super.viewDidLoad() title = K.Generic_Text.scrittaInserisci navigationItem.hidesBackButton = true labelTutorialInserisci.text = K.App_Text.tutorialInserisci // 首先获取"utenti"集合引用 let utentiCollectionRef = Firestore.firestore().collection("utenti") // 查询每个用户的"positive"和"negative"集合 utentiCollectionRef.getDocuments { (snapshot, error) in if let error = error { print("获取文档错误: \(error.localizedDescription)") return } var transactions: [Transaction] = [] for _ in snapshot!.documents { // 获取当前用户ID let userId = self.user!.uid // 查询"positive"集合中最新的一条记录(按日期倒序) let positiveCollectionRef = utentiCollectionRef.document(self.user!.uid).collection("transactions").document("transactions").collection("positive") positiveCollectionRef.order(by: "data", descending: true).limit(to: 1).getDocuments { (snapshot, error) in if let error = error { print("获取文档错误: \(error.localizedDescription)") return } // 解析数据并添加到交易数组 for document in snapshot!.documents { let data = document.data() let name = data["name"] as! String let number = data["number"] as! Double let date = data["data"] as! Timestamp transactions.append(Transaction(userId: userId, name: name, type: .positive, amount: number, date: date.dateValue())) } } // 查询"negative"集合中最新的一条记录(按日期倒序) let negativeCollectionRef = utentiCollectionRef.document(self.user!.uid).collection("transactions").document("transactions").collection("negative") negativeCollectionRef.order(by: "data", descending: true).limit(to: 1).getDocuments { (snapshot, error) in if let error = error { print("获取文档错误: \(error.localizedDescription)") return } // 解析数据并添加到交易数组 for document in snapshot!.documents { let data = document.data() let name = data["name"] as! String let number = data["number"] as! Double let date = data["data"] as! Timestamp transactions.append(Transaction(userId: userId, name: name, type: .negative, amount: number, date: date.dateValue())) } } } // 所有查询完成后,按日期排序并刷新Table View transactions.sort { $0.date > $1.date } self.tableView.reloadData() } } }
日志截图

问题排查与修复方案
核心问题1:异步请求时序错误
Firestore的getDocuments是异步操作,你在发起两个异步查询后立刻执行排序和刷新Table View的代码,但此时异步请求还未完成,transactions数组仍为空,导致Table View无数据。
核心问题2:局部变量覆盖全局数组
闭包内部声明的var transactions: [Transaction] = []覆盖了类的全局transactions数组,即使异步请求获取到数据,也不会更新到Table View依赖的数据源中。
核心问题3:不必要的全用户遍历
先获取utenti集合所有文档再循环查询当前用户数据完全多余,直接针对当前用户ID查询即可。
核心问题4:未设置Table View数据源与代理
类未遵守UITableViewDataSource协议,也未设置tableView.dataSource = self,Table View无法获取行数和单元格数据。
修复后的代码
import UIKit import Firebase class InserisciViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var labelTutorialInserisci: UILabel! @IBOutlet weak var buttonEntrate: UIButton! @IBOutlet weak var buttonUscite: UIButton! @IBOutlet weak var tableView: UITableView! var transactions: [Transaction] = [] let db = Firestore.firestore() let user = Auth.auth().currentUser struct Transaction { let userId: String let name: String let type: TransactionType let amount: Double let date: Date } enum TransactionType { case positive case negative } override func viewDidLoad() { super.viewDidLoad() title = K.Generic_Text.scrittaInserisci navigationItem.hidesBackButton = true labelTutorialInserisci.text = K.App_Text.tutorialInserisci // 设置Table View数据源与代理 tableView.dataSource = self tableView.delegate = self fetchTransactions() } private func fetchTransactions() { guard let userId = user?.uid else { print("用户未登录") return } // 构造两个集合的查询引用 let positiveRef = db.collection("utenti").document(userId) .collection("transactions").document("transactions").collection("positive") .order(by: "data", descending: true).limit(to: 1) let negativeRef = db.collection("utenti").document(userId) .collection("transactions").document("transactions").collection("negative") .order(by: "data", descending: true).limit(to: 1) // 使用DispatchGroup等待两个异步请求完成 let group = DispatchGroup() group.enter() positiveRef.getDocuments { [weak self] snapshot, error in defer { group.leave() } guard let self = self, let snapshot = snapshot, error == nil else { print("获取positive数据失败: \(error?.localizedDescription ?? "未知错误")") return } for doc in snapshot.documents { let data = doc.data() guard let name = data["name"] as? String, let number = data["number"] as? Double, let timestamp = data["data"] as? Timestamp else { continue } self.transactions.append(Transaction(userId: userId, name: name, type: .positive, amount: number, date: timestamp.dateValue())) } } group.enter() negativeRef.getDocuments { [weak self] snapshot, error in defer { group.leave() } guard let self = self, let snapshot = snapshot, error == nil else { print("获取negative数据失败: \(error?.localizedDescription ?? "未知错误")") return } for doc in snapshot.documents { let data = doc.data() guard let name = data["name"] as? String, let number = data["number"] as? Double, let timestamp = data["data"] as? Timestamp else { continue } self.transactions.append(Transaction(userId: userId, name: name, type: .negative, amount: number, date: timestamp.dateValue())) } } // 所有请求完成后,排序并刷新Table View group.notify(queue: .main) { [weak self] in guard let self = self else { return } self.transactions.sort { $0.date > $1.date } self.tableView.reloadData() } } // MARK: - UITableViewDataSource func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return transactions.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // 替换成你在Storyboard中设置的Cell标识符 let cell = tableView.dequeueReusableCell(withIdentifier: "TransactionCell", for: indexPath) let transaction = transactions[indexPath.row] cell.textLabel?.text = transaction.name cell.detailTextLabel?.text = "\(transaction.type == .positive ? "+" : "-")\(transaction.amount)" return cell } }
额外注意事项
- 确保Storyboard中Table View的Cell已设置正确的标识符,并与代码中
dequeueReusableCell的参数一致。 - 用可选绑定替代强制解包(
as!换成as?),避免因数据格式错误导致崩溃。 - 使用
[weak self]避免循环引用,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

