Swift 4中无法将Firebase数据库数据存入数组并在TableView展示
解决Firebase异步加载导致TableView无数据展示的问题
嘿,我太懂你现在的困扰了——这其实是Firebase异步数据加载的典型“坑”!你写的getOrders()函数里藏着关键问题:observe(.value)的回调是异步执行的,等它从Firebase拉完数据、把内容塞进tempArray的时候,函数早已经把空的tempArray返回给orders了,所以numberOfRowsInSection拿到的自然是空数组,TableView当然生成不了单元格啦。
下面是具体的修复方案,我一步步给你拆解:
1. 重构数据加载逻辑,放弃从异步回调返回值
异步操作里不能试图直接返回数据,正确的做法是:在回调完成后更新数据源数组,再主动通知TableView刷新。
2. 修正后的完整代码
class OrdersPage: UIViewController, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return orders.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath) as! OrderCell cell.setOrder(order: orders[indexPath.row]) print("Adding new cell") return cell } @IBOutlet weak var tableView: UITableView! var ref: DatabaseReference! var orders = [Order]() override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self self.ref = Database.database().reference() // 直接调用加载方法,不用赋值 fetchOrders() } // 修改方法逻辑:专注于加载数据+刷新UI func fetchOrders() { ref.child("Orders").observe(.value) { [weak self] (snapshot) in guard let self = self else { return } var tempArray = [Order]() for child in snapshot.children { let orderDB = child as! DataSnapshot // 用可选绑定代替强制解包,避免数据格式错误导致崩溃 guard let orderDict = orderDB.value as? [String: Any] else { print("解析订单数据失败:\(orderDB.key)") continue } guard let name = orderDict["name"] as? String, let date = orderDict["date"] as? String, let time = orderDict["time"] as? String, let hotel = orderDict["hotel"] as? String, let room = orderDict["room"] as? String, let airport = orderDict["airport"] as? String, let agent = orderDict["agent"] as? String, let price = orderDict["price"] as? String else { print("订单\(orderDB.key)缺少必填字段") continue } tempArray.append(Order(name: name, date: date, time: time, hotel: hotel, room: room, airport: airport, agent: agent, price: price)) } // 更新数据源 self.orders = tempArray // 回到主线程刷新UI(Firebase回调在后台线程,UI操作必须在主线程) DispatchQueue.main.async { self.tableView.reloadData() } } } }
额外小贴士
- 尽量用可选绑定代替
as!强制解包:如果Firebase里的数据格式有偏差,强制解包会直接导致崩溃,可选绑定能让你优雅处理错误。 - 加上
[weak self]避免循环引用:防止ViewController因为Firebase的监听而无法被释放,造成内存泄漏。 - 优化监听方式:如果只需要监听新增订单,用
observe(.childAdded)代替observe(.value),不用每次全量刷新列表,性能会更好。
内容的提问来源于stack exchange,提问作者Andrei Georgescu
相关产品推荐
相关产品推荐

