删除UITableView最后一个Cell触发Invalid update错误求助
iOS UITableView滑动删除最后一个Cell报错的原因与修复方案
问题现象
滑动删除UITableView的Cell时多数场景功能正常,但删除最后一个Cell时会触发如下错误:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to...
错误原因
你的numberOfRowsInSection方法做了特殊处理:当resultArray为空时返回1(用来显示空状态提示Cell)。但删除最后一个元素后,你只更新了数据源,却没有正确同步UITableView的更新逻辑:
- 删除最后一个Cell前,
resultArray.count为1,tableView显示1行; - 删除元素后,
resultArray变为空,此时numberOfRowsInSection应该返回1; - 但SwipeCell的
.destructive扩展样式默认会告诉tableView「删除1行,行数从1变为0」,这和你数据源返回的行数1产生冲突,触发了iOS的tableView更新校验错误。
修复方案
方案一:修改删除回调的tableView更新逻辑
在删除数据源后,根据数组是否为空选择不同的tableView更新方式:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? { guard orientation == .right else { return nil } let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in // 移除数据源元素 self.resultArray.remove(at: indexPath.row) // 保存数据到本地 let encoder = PropertyListEncoder() do { let data = try encoder.encode(self.resultArray) try data.write(to: self.filePath!) } catch { print("There was an error saving data: \(error)") } // 同步更新tableView if self.resultArray.isEmpty { // 数组为空时,直接刷新整个tableView,显示空状态Cell self.resultsTableView.reloadData() } else { // 数组还有元素时,删除指定行 self.resultsTableView.deleteRows(at: [indexPath], with: .automatic) } } deleteAction.image = UIImage(named: "deleteIcon") return [deleteAction] }
方案二:改用BackgroundView实现空状态(更推荐)
把空状态提示从Cell改为tableView的backgroundView,这样numberOfRowsInSection可以直接返回数据源长度,避免行数计算冲突:
- 修改
numberOfRowsInSection方法:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return resultArray.count }
- 添加空状态更新方法:
private func updateEmptyState() { if resultArray.isEmpty { // 创建空状态提示Label let emptyLabel = UILabel() emptyLabel.text = "No Saved Results Yet." emptyLabel.font = UIFont(name: "Caveat", size: 30.0) emptyLabel.textAlignment = .center emptyLabel.backgroundColor = blueCell // 设置为tableView的背景视图 resultsTableView.backgroundView = emptyLabel resultsTableView.separatorStyle = .none } else { // 有数据时恢复默认背景和分隔线 resultsTableView.backgroundView = nil resultsTableView.separatorStyle = .singleLine } }
- 在数据更新的地方调用该方法:
- 在
loadCellName末尾添加:
resultArray = decodedData updateEmptyState() self.resultsTableView.reloadData()
- 在删除回调中添加:
self.resultArray.remove(at: indexPath.row) // 保存数据... updateEmptyState() self.resultsTableView.deleteRows(at: [indexPath], with: .automatic)
这种方式更符合UITableView的设计规范,也能彻底避免行数不匹配的问题。
内容的提问来源于stack exchange,提问作者Jake Jake
相关产品推荐
相关产品推荐

