Swift开发:TableView加载Firestore数据后滚动时Cell消失问题求解
问题根因分析
- 越界判断逻辑存在漏洞:如果
myRatingsRestaurant数组为空时,myRatingsRestaurant.count-1结果为-1,此时indexPath.row=0会命中判断返回无内容的空UITableViewCell,就是你看到的Cell消失的情况;如果你的numberOfRowsInSection代理方法返回的行数大于数组实际长度,也会频繁触发这个逻辑返回空Cell。 - 异步数据同步不及时:Firestore拉取数据是异步操作,如果你更新
myRatingsRestaurant数组后没有立刻在主线程调用TableView的刷新方法,就会出现TableView已经要求渲染对应索引的Cell,但数组还没完成更新的情况,直接触发你标注的索引越界崩溃。 - 冗余代码存在隐患:给Cell设置tag的代码完全不需要,Cell复用过程中tag会不断被覆盖,后续如果通过tag取值会出现逻辑错乱。
修复方案
首先替换cellForRowAt的代码为更安全的写法:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // 先判断索引是否在合法范围内,写法更直观 guard indexPath.row < myRatingsRestaurant.count else { // 如果是分页加载的占位Cell可以在这里返回你的加载态Cell,否则兜底返回空Cell return UITableViewCell() } // 把强制类型转换改成可选绑定,避免类型不匹配直接崩溃 guard let cell = tableView.dequeueReusableCell(withIdentifier: "MyRatingsViewCell", for: indexPath) as? MyRatingsViewCell else { return UITableViewCell() } let myRatingRestaurant = myRatingsRestaurant[indexPath.row] cell.set(myRatingRestaurant: myRatingRestaurant) return cell }
接下来按顺序检查以下配置:
- 核对
numberOfRowsInSection代理的返回值,确保返回的行数和myRatingsRestaurant的长度完全一致;如果是做分页加载多返回了1个加载占位Cell,要在数组更新后同步调整返回值,避免返回的行数比数组实际元素多。 - 检查Firestore数据请求的回调逻辑,拿到数据更新
myRatingsRestaurant数组后,必须切换到主线程刷新列表,参考写法:
// Firestore异步请求示例 db.collection("你的集合名称").getDocuments { [weak self] snapshot, error in guard let self = self, let documents = snapshot?.documents else { return } // 解析数据更新数组 self.myRatingsRestaurant = documents.compactMap { try? $0.data(as: MyRatingRestaurant.self) } // 必须切换到主线程刷新列表 DispatchQueue.main.async { self.tableView.reloadData() } }
- 如果你做了上拉分页加载,每次拿到新数据是往
myRatingsRestaurant数组末尾追加元素,追加完成后同样要在主线程调用reloadData()或者insertRows(at:with:)批量插入新Cell,禁止修改数组后不触发列表刷新。
内容的提问来源于stack exchange,提问作者joeythefoodie
相关产品推荐
相关产品推荐

