如何基于UITableViewDiffableDataSource实现UITableView滑动删除?
解决UITableViewDiffableDataSource下的滑动删除问题
你遇到的崩溃是因为直接调用tableView.deleteRows违反了DiffableDataSource的更新规则——所有表格更新必须通过snapshot + apply的方式,不能直接操作表格行。以下是正确的实现方案:
核心修正点
- 滑动删除是
UITableViewDelegate的职责,直接让ViewController作为表格的delegate实现对应方法即可,无需自定义数据源协议。 - 删除操作必须先更新数据模型,再通过生成新的
snapshot并应用到数据源来触发表格更新。
修改后的代码实现
1. 完善ViewController的配置
确保初始化数据源时设置表格的delegate为当前控制器,并修正滑动删除的动作逻辑:
class ViewController: UIViewController, UITableViewDelegate { @IBOutlet var tableView: UITableView! var items = [Item]() var tableViewDataSource: ItemsTableViewDiffableDataSource! var itemsSnapshot: NSDiffableDataSourceSnapshot<String, Item> { var snapshot = NSDiffableDataSourceSnapshot<String, Item>() snapshot.appendSections(["Items"]) snapshot.appendItems(items) return snapshot } func configureTableViewDataSource() { // 初始化自定义数据源 tableViewDataSource = ItemsTableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in // 替换为你的cell配置逻辑 let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellID", for: indexPath) cell.textLabel?.text = item.title // 假设Item有title属性 return cell } // 设置表格delegate为当前控制器 tableView.delegate = self // 初始加载数据 tableViewDataSource.apply(itemsSnapshot) } func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let deleteAction = UIContextualAction(style: .destructive, title: "删除") { [weak self] action, view, completionHandler in guard let self = self else { completionHandler(false) return } // 1. 从数据模型中移除对应元素 let deletedItem = self.items.remove(at: indexPath.row) // 2. 生成新的snapshot并应用到数据源 var snapshot = self.itemsSnapshot snapshot.deleteItems([deletedItem]) self.tableViewDataSource.apply(snapshot, animatingDifferences: true) // 3. 通知系统动作完成 completionHandler(true) } deleteAction.backgroundColor = .red let configuration = UISwipeActionsConfiguration(actions: [deleteAction]) configuration.performsFirstActionWithFullSwipe = false return configuration } }
2. 简化自定义DataSource类
不需要额外协议,保持基础定义即可:
@MainActor class ItemsTableViewDiffableDataSource: UITableViewDiffableDataSource<String, Item> { }
关键说明
- 为什么不能直接操作表格行?:DiffableDataSource通过
snapshot维护表格状态,直接调用deleteRows会导致数据源与表格状态不一致,触发崩溃提示的错误。 - 为什么之前的协议方式无效?:滑动删除是
UITableViewDelegate的方法,你之前未将ViewController设置为表格的delegate,所以方法不会被触发。 - 弱引用的作用:在闭包中使用
[weak self]避免循环引用,防止控制器无法被正确释放。
内容的提问来源于stack exchange,提问作者ASCIImo
相关产品推荐
相关产品推荐

