Неверный IndexPath после вставки / удаления ячейки из UITableView - PullRequest
0 голосов
/ 27 февраля 2019

Код

Основы для проблемных частей 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, будет неправильным (будет равно значению до удаления ячейки).

Мне кажется, я знаю, почему

  1. IndexPath является структурой, поэтому handleDidChangeSelectionState сохраняет копию текущего значения (не экземпляра).Любое обновление исходного значения не будет обновлять захваченную копию.
  2. 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:))

Может быть, есть третий подход лучше.

Спасибо за любой совет.

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Не используйте перезагрузку определенной строки, потому что индекс был изменен при удалении строки, и он удалит анимацию после удаления строки, поэтому вам нужно перезагрузить 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()
    })
0 голосов
/ 27 февраля 2019

Только подход 1st удовлетворяет первому условию, чтобы сохранял плавные анимации .Вызов reloadData сразу после deleteRows прерывает анимацию.

И вызов indexPath(for: cell), безусловно, дешевле, чем перезагрузка всего табличного представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...