TableView行需删除两次才消失?滑动删行仅删文本且调用deleteRows崩溃求助
解决TableView滑动删除行的崩溃与UI不同步问题
我来帮你拆解下代码里的几个核心问题,一步步搞定这个删除异常:
原代码的关键错误
- 错误覆盖数据源数组:你在删除后执行了
self.messages = deleteMessage,而deleteMessage是fetch了所有Messages对象,等于把刚删掉的元素又重新加回了数据源,这就是为什么要删两次UI才会变化——第一次删完又把数据加载回来了! - Core Data与数据源操作顺序混乱:你先从数组移除元素再删除Core Data对象,虽然逻辑上能删,但后续的错误赋值导致白忙活;而且直接调用
reloadData而不是针对性的deleteRows,既不流畅还容易引发同步问题。 - 缺少错误处理:保存Core Data上下文时没有捕获异常,一旦保存失败会导致数据源和UI彻底不一致,甚至崩溃。
修正后的完整代码
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { guard editingStyle == .delete else { return } // 1. 先拿到要删除的对象(从数据源数组中获取) let targetMessage = messages[indexPath.row] // 2. 从Core Data上下文删除对象 PersistenceServce.context.delete(targetMessage) // 3. 从本地数据源数组移除元素(必须在UI更新前完成) messages.remove(at: indexPath.row) do { // 4. 保存Core Data上下文,持久化删除操作 try PersistenceServce.saveContext() // 5. 通知TableView删除对应行(数据源已更新,不会崩溃) tableView.deleteRows(at: [indexPath], with: .automatic) } catch { // 保存失败时,把元素加回数组,避免数据源和UI不一致 messages.insert(targetMessage, at: indexPath.row) print("删除操作失败:\(error.localizedDescription)") // 这里可以给用户弹出提示,比如AlertController } }
关键修复点说明
- 先更新数据源,再更新UI:必须确保
messages数组先移除对应元素,再调用deleteRows,这样TableView的数据源和UI状态一致,不会触发崩溃。 - 取消多余的fetch操作:不需要重新获取所有数据,直接操作本地数组即可,既高效又避免同步错误。
- 完善错误处理:保存失败时回滚数组操作,防止出现数据源和UI脱节的情况。
额外注意事项
- 确保
messages是TableView的唯一数据源,所有数据更新都要通过修改这个数组来完成,不要在其他地方随意覆盖它。 - 如果你的TableView实例是
SavedMessages,那把代码里的tableView换成SavedMessages也可以,但更推荐用方法参数里的tableView,复用性更好。
内容的提问来源于stack exchange,提问作者Carter Cobb
相关产品推荐
相关产品推荐

