如何实现UITableView侧滑删除功能且规避NSInternalInconsistencyException异常?
搞定UITableView侧滑删除的NSInternalInconsistencyException崩溃问题
兄弟,这个崩溃的原因其实一眼就能看出来——你本地的数据源数组items和UITableView显示的行数没同步上!
你看现在的流程:调用Firebase删除数据后,直接让表格删一行,紧接着又调用reloadData()。但你根本没把items数组里对应的元素删掉啊!这就导致表格刚删完一行变成6行,reloadData又让它从items里读7行,系统一看数据对不上,直接就抛出异常了。
而且还有个隐藏问题:Firebase的removeValue()是异步操作,你不能在它调用完立刻就改UI,得等它真正删除成功之后再处理本地数据和表格。
给你整理好的修复步骤:
- 先在Firebase删除的回调里,把本地
items数组里对应的元素删掉 - 把多余的
tableView.reloadData()删掉,用deleteRows来做局部更新就行 - 所有UI操作要放在主线程里执行
修改后的完整代码:
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { guard let uid = Auth.auth().currentUser?.uid else { return } guard let itemId = items[indexPath.item].itemId else { return } // 异步删除Firebase数据,在回调里处理后续逻辑 USER_BAG_REF.child(uid).child(itemId).removeValue { error, _ in if let error = error { // 删除失败的情况可以加个提示,比如弹个Alert print("删不掉啊兄弟:\(error.localizedDescription)") return } // 第一步:先更新本地数据源,这是关键! self.items.remove(at: indexPath.item) // 第二步:主线程更新表格UI DispatchQueue.main.async { tableView.deleteRows(at: [indexPath], with: .fade) } } } else if editingStyle == .insert { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. } }
为啥这么改?给你掰扯清楚:
- 异步回调处理:Firebase删数据是网络请求,得等它返回成功再改本地数据,不然万一网络卡了,本地删了但云端没删,数据就乱了
- 先改数据源再更UI:UITableView特别认死理,数据源有多少行,它就得显示多少行。所以必须先把
items里的元素删掉,再告诉表格删哪一行 - 去掉reloadData:
deleteRows已经是精准更新某一行了,再调用reloadData会让整个表格重新刷新,既慢又容易出问题 - 主线程更新UI:iOS里所有UI操作都得在主线程干,不然容易出各种奇怪的bug,所以用
DispatchQueue.main.async包一下
这样改完之后,数据源和表格行数就完全匹配了,再也不会崩那个NSInternalInconsistencyException了,而且Firebase删成功之后才会更新本地,数据也不会乱。
内容的提问来源于stack exchange,提问作者es915
相关产品推荐
相关产品推荐

