Ios 从UITableView插入/删除单元格后的IndexPath错误 密码
VC问题部分的要点:Ios 从UITableView插入/删除单元格后的IndexPath错误 密码,ios,swift,uitableview,Ios,Swift,Uitableview,VC问题部分的要点: // Part of VC where cell is setting func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(for: indexPath) as Cell let cellVM = viewModel.cellVM(
// Part of VC where cell is setting
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(for: indexPath) as Cell
let cellVM = viewModel.cellVM(for: indexPath)
cell.update(with: cellVM)
cell.handleDidChangeSelectionState = { [weak self] selected in
guard
let `self` = self
else { return }
self.viewModel.updateSelectionState(selected: selected, at: indexPath)
}
return cell
}
// Part of code where cell can be deleted
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .destructive, title: "delete".localized, handler: { [weak self] _, indexPath in
guard let self = self else { return }
self.viewModel.delete(at: indexPath)
tableView.deleteRows(at: [indexPath], with: .left)
})
return [deleteAction]
}
问题
当单元格被删除后,将涉及handledChangeSelectionState
,然后将indepath
传递到viewModel。updateSelectionState
将出错(将等于单元格删除前的值)
我想我知道为什么
indepath
是一个结构,因此handledChangeSelectionState
保留当前值(而不是实例)的副本。原始值的任何更新都不会更新捕获的副本tableView.deleteRows
不会重新加载tableView的数据源,因此cellForRowAt
不会调用。这意味着handledChangeSelectionState
将不会捕获更新的副本处理的IDChangeSelectionState中的indexPath值:
cell.handleDidChangeSelectionState = { [weak self, weak cell] selected in
guard
let `self` = self,
let cell = cell,
// now I have a correct value
let indexPath = tableView.indexPath(for: cell)
else { return }
self.viewModel.updateSelectionState(selected: selected, at: indexPath)
}
*第二
每次删除后执行重新加载数据()
:
问题
哪种方法更好
我想:
- 保持动画流畅(得益于
tableView.deleteRows(位于:[]
)
- 找到更好的性能(我不确定哪一个更优化,
reloadData()
或indepath(对于单元格:)
)
也许有更好的第三种方法
感谢您的建议。只有1st方法满足保持动画平滑的第一个条件。在deleteRows
之后立即调用reloadData
会中断动画
调用indexPath(for:cell)
肯定比重新加载整个表视图便宜。不要使用重新加载特定行,因为删除行时索引已更改,删除行后它将删除动画,这就是为什么需要重新加载tableview.reloadData()
在您的情况下,这是一个更好的选择
let deleteAction = UITableViewRowAction(style: .destructive, title: "delete".localized, handler: { [weak self] _, indexPath in
guard let self = self else { return }
self.viewModel.delete(at: indexPath)
tableView.deleteRows(at: [indexPath], with: .left)
// force to recall `cellForRowAt` then `handleDidChangeSelectionState` will capture correct value
tableView.reloadData()
})
let deleteAction = UITableViewRowAction(style: .destructive, title: "delete".localized, handler: { [weak self] _, indexPath in
guard let self = self else { return }
self.viewModel.delete(at: indexPath)
tableView.deleteRows(at: [indexPath], with: .left)
// force to recall `cellForRowAt` then `handleDidChangeSelectionState` will capture correct value
tableView.reloadData()
})