Обновлять значение indexPath после удаления строки

#swift #uitableview #asynchronous

#swift #uitableview #асинхронный

Вопрос:

У меня есть список любимых фильмов. В ячейке таблицы есть кнопка для удаления фильма из списка избранного. Итак, я хочу анимировать его с помощью TableView.deleteRows. Но если я удалю строку из верхней части экрана, другие строки поднимутся вверх. Это нормально, но когда я удалял строку из верхней части экрана, другие ячейки, которые уже показаны в списке, не обновляли indexPath. Я назначаю метод asyncAfter для TableView.reloadData для решения проблемы, но я думаю, что это может привести к сбою на стороне операционной системы. Потому что я заставил основной поток перезагрузить данные после задержки. Действительно ли это проблема для ОС и что мне делать?

Пример проблемы:

Если я удалю фильм с индексом 0, все фильмы будут увеличиваться. Таким образом, перед удалением у 1 индексного фильма должен быть индекс 0, но это не так. Если я попытался удалить новый фильм с индексом 0, он удаляет другой фильм.

Пример работы без TableView.reloadData()

Вот мой код // Это работает, но я думаю, что проблема в asyncAfter

 cell.deleteButtonActionBlock = {
    FavouritesHandler.shared.deleteMovie(movie)
    self.tableView.deleteRows(at: [indexPath], with: .automatic)
    DispatchQueue.main.asyncAfter(deadline: .now()   0.3) {
        self.tableView.reloadData()
    }
}
  

Комментарии:

1. Вы ранее удаляли элемент из массива datasource tableView.deleteRows ?

2. @Jithin да, favoriteshandler.shared. deleteMovie (фильм) удаление фильма из массива

3. Я предполагаю, что что-то не так в том, как вы фиксируете путь к индексу.

4. @vadian этот фрагмент в TableView cellForRowAt использует indexPath, я так не думаю

5. Я делаю, это именно проблема. Пожалуйста, посмотрите мой ответ.

Ответ №1:

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

В пользовательской ячейке объявить закрытие

 var deleteButtonActionBlock : ((UITableViewCell) -> Void)?
  

и вызвать его

 deleteButtonActionBlock?(self)
  

В cellForRow получите фактический путь к индексу для ячейки

 cell.deleteButtonActionBlock = { aCell in
    let actualIndexPath = tableView.indexPath(for: aCell)!
    FavouritesHandler.shared.deleteMovie(movie)
    tableView.deleteRows(at: [actualIndexPath], with: .automatic)
}
  

Не требуется (уродливая) задержка и (бессмысленная) перезагрузка.

Пожалуйста, обратите внимание также, что я удалил self в delete строке, потому что экземпляр TableView доступен в качестве параметра метода.

Комментарии:

1. Большое вам спасибо. Не могли бы вы, пожалуйста, объяснить, почему захваченный indexPath не работает должным образом? Это моя вторая неделя в Swift 🙂

2. Да, термин » захват » содержит объяснение. В тот момент, когда вы назначаете закрытие, путь к индексу заморожен и больше не изменяется. Это приводит к неожиданному поведению.

3. Если я не ошибаюсь, при использовании cellForRowAt indexPath обновляется при изменении ячейки. Но с использованием closure я передал его, когда я использую deleteButton. Я действительно ценю вас. Большое спасибо за вашу помощь.

4. cellForRow не вызывается снова после delete-/insertRows