Код
Основы для проблемных частей 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(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]
}
Проблема
Когда ячейка была удалена и после этого будет задействована handleDidChangeSelectionState
, тогда *Значение 1009 *, переданное в viewModel.updateSelectionState
, будет неправильным (будет равно значению до удаления ячейки).
Мне кажется, я знаю, почему
IndexPath
является структурой, поэтому handleDidChangeSelectionState
сохраняет копию текущего значения (не экземпляра).Любое обновление исходного значения не будет обновлять захваченную копию. tableView.deleteRows
не будет перезагружать источник данных просмотра таблицы, поэтому cellForRowAt
не будет вызывать.Это означает, что handleDidChangeSelectionState
не будет захватывать обновленную копию.
Мой подход к решению этой проблемы
* 1-й
Спросите о значении indexPath внутри handleDidChangeSelectionState
:
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)
}
* 2-й
После каждого удаления выполните 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()
})
Вопрос
Какой подход лучше?
Я хочу:
- сохранять плавную анимацию (благодаря
tableView.deleteRows(at: []
) - найти лучшую производительность (я не уверен, что является более оптимальным,
reloadData()
или indexPath(for cell:)
)
Может быть, есть третий подход лучше.
Спасибо за любой совет.