为何从Firestore获取数据的TableView无法更新单元格?
问题分析与解决方案
核心问题
- 数据源不同步:TableView的数据源是
searchReservations,但loadReservations仅更新Reservations数组,刷新操作未将新数据同步到searchReservations,导致UI仍显示旧内容。 - 异步操作顺序错误:
refresh方法中调用loadReservations后立刻执行reloadData和endRefreshing,但Firestore的getDocuments是异步请求,此时数据还未加载完成,刷新操作无效。 - 频繁刷新效率低下:
loadReservations循环内每次添加数据都调用reloadData,既浪费资源又可能导致UI闪烁。
修复步骤与代码修改
1. 修正refresh方法逻辑
移除异步块内的提前刷新操作,仅触发数据加载,后续刷新逻辑交给Firestore回调处理:
@objc func refresh(send: UIRefreshControl) { // 清空数组避免数据重复 self.Reservations.removeAll() self.loadReservations() }
2. 同步数据源并统一刷新时机
在Firestore数据加载完成后,同步searchReservations并统一刷新TableView,同时结束刷新控件:
func loadReservations() { Reservations = [] guard let uid = Auth.auth().currentUser?.uid else { return } let userCollection = Firestore.firestore().collection("Users") let thisUserDoc = userCollection.document(uid) thisUserDoc.collection("Reservations").getDocuments { (querySnapshot, error) in if let e = error { print(e) // 加载失败也要结束刷新 DispatchQueue.main.async { self.refreshControl.endRefreshing() } return } guard let snapshotDocuments = querySnapshot?.documents else { DispatchQueue.main.async { self.refreshControl.endRefreshing() } return } for doc in snapshotDocuments { let data = doc.data() if let Time = data["Time"] as? String, let Date = data["Date"] as? String, let Guests = data["Guests"] as? String, let RestaurantName = data["RestaurantName"] as? String, let Name = data["Name"] as? String, let Status = data["Status"] as? String, let Phone = data["Phone"] as? String, let Id = data["Id"] as? String, let RestaurantId = data["RestaurantID"] as? String, let Id2 = data["Id2"] as? String, let guestId = data["GuestId"] as? String { let newReservation = Reservation(id: Id, userId: guestId, id2: Id2,restaurantId: RestaurantId ,restaurantName: RestaurantName, name: Name, phone: Phone, guests: Guests, time: Time, date: Date, status: Status) self.Reservations.append(newReservation) } } // 所有数据加载完成后同步数据源并刷新UI DispatchQueue.main.async { self.searchReservations = self.Reservations self.reservationsTableView.reloadData() self.refreshControl.endRefreshing() } } }
3. 移除循环内的局部刷新
删除loadReservations循环中的DispatchQueue.main.async { self.reservationsTableView.reloadData() },改为统一刷新。
额外优化建议
- 遵循Swift命名规范:变量名首字母小写(如
Reservations改为reservations),提升代码可读性。 - 若
searchReservations用于搜索过滤,可在loadReservations完成后调用过滤逻辑再赋值,确保搜索状态下刷新也能正确显示结果。
内容的提问来源于stack exchange,提问作者Branislav Fekeč
相关产品推荐
相关产品推荐

