ReloadRowsAtIndexPaths: withRowAnimation: сбой моего приложения
У меня возникла странная проблема с моим UITableView: я использую reloadRowsAtIndexPaths:withRowAnimation:
для перезагрузки некоторых определенных строк, но приложение выходит из строя с кажущимся несвязанным исключением: NSInternalInconsistencyException - Попытка удалить больше строк, чем существует в разделе.
Мой код выглядит следующим образом:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
Когда я заменяю это сообщение reloadRowsAtIndexPaths:withRowAnimation:
простым reloadData
, он отлично работает.
Любые идеи?
Ответы
Ответ 1
Проблема в том, что вы, вероятно, изменили размер своей таблицы. Например, вы добавляете или удаляете некоторые исходные данные для представления таблицы.
В этом случае, когда вы вызываете reloadData
, ваша таблица полностью перезагружается, включая размеры разделов и количество этих разделов.
Но когда вы вызываете reloadRowsAtIndexPaths:withRowAnimation:
, параметры вашего представления таблицы не перезагружаются. Это вызывает следующую проблему: когда вы пытаетесь перезагрузить некоторую таблицу ячеек, проверьте размер табличного представления и увидите, что он был изменен. Это приводит к сбою. Этот метод может использоваться только тогда, когда вы не хотите перезагружать представление ячейки (например, метка изменилась или вы хотите изменить ее размер).
Теперь, если вы хотите удалить/добавить ячейки из/в представление таблицы, вы должны использовать следующий подход:
- Сообщите таблице, что ее размер будет изменен путем вызова метода
beginUpdates
из UITableView
- Сообщите о вставке новых строк с помощью метода
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
- Сообщите об удалении строк с помощью метода
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
- Сообщите таблице, что ее размер был изменен путем вызова метода
endUpdates
в UITableView
Надеюсь, что это будет полезно
Ответ 2
Я думаю, что следующий код может работать:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
Ответ 3
У меня была эта проблема, вызванная вызовом блока reloadRowsAtIndexPaths: withRowAnimation: и параллельный поток, вызывающий reloadData.
Сбой произошел из-за reloadRowsAtIndexPaths: withRowAnimation обнаружил пустую таблицу, несмотря на то, что я проверял работоспособность numberOfRowsInSection и numberOfSections.
Я принял такое отношение, что мне все равно, вызывает ли это исключение. Визуальное повреждение, с которым я мог бы жить как пользователь приложения, чем сбой всего приложения.
Вот мое решение, которое я с удовольствием разделяю и буду приветствовать конструктивную критику. Если есть лучшее решение, которое я хочу услышать?
- (void) safeCellUpdate: (NSUInteger) section withRow : (NSUInteger) row {
// It important to invoke reloadRowsAtIndexPaths implementation on main thread, as it wont work on non-UI thread
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger lastSection = [self.tableView numberOfSections];
if (lastSection == 0) {
return;
}
lastSection -= 1;
if (section > lastSection) {
return;
}
NSUInteger lastRowNumber = [self.tableView numberOfRowsInSection:section];
if (lastRowNumber == 0) {
return;
}
lastRowNumber -= 1;
if (row > lastRowNumber) {
return;
}
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
@try {
if ([[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] == NSNotFound) {
// Cells not visible can be ignored
return;
}
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
@catch ( NSException *e ) {
// Don't really care if it doesn't work.
// It just to refresh the view and if an exception occurs it most likely that that is what happening in parallel.
// Nothing needs done
return;
}
});
}
Ответ 4
ЭТО СТАРЫЙ. НЕ ИСПОЛЬЗУЙ.
Я просто столкнулся с этой проблемой, когда я вызывал reloadRowsAtIndexPaths...
, чтобы изменить ячейку на ячейку редактирования, содержащую UITextField
. Ошибка сказала мне, что я удаляю все строки в таблице. Чтобы решить проблему, я удалил:
[self.tableView beginUpdates];
NSArray *reloadIndexPath = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:section]];
[self.tableView reloadRowsAtIndexPaths:reloadIndexPath withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
и заменил его на
[self.tableView reloadData];
Ответ 5
После многих попыток я обнаружил, что "reloadRowsAtIndexPaths" может использоваться только в определенных местах, если только изменить содержимое ячейки, а не вставлять или удалять ячейки. Ни одно место не может использовать его, даже вы оберните его в
[self beginUpdates];
//reloadRowsAtIndexPaths
[self endUpdates];
Места, которые я нашел, могут использовать:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (IBAction) unwindToMealList: (UIStoryboardSegue *) sender
Любая попытка из других мест, например, вызвать его из "viewDidLoad" или "viewDidAppear", либо не вступит в силу (для уже загруженной ячейки я имею в виду, что перезагрузка не вступает в силу) или вызывают исключение.
Поэтому старайтесь использовать "reloadRowsAtIndexPaths" только в этих местах.
Ответ 6
У меня была такая же проблема. В моем случае; это происходило только в том случае, если другой контроллер представления pop/нажал на существующий контроллер табличного представления, а затем вызывается функция [self.tableView reloadRowsAtIndexPaths].
reloadRowsAtIndexPaths вызов скрывал/показывал разные строки в представлении таблицы, которое имеет более 30, визуально сложных строк. Поскольку я пытаюсь исправить проблему, я обнаружил, что если бы я слегка прокрутил приложение для просмотра таблицы, это не сбой. Кроме того, это не сбой, если я не скрываю ячейку (возвращая 0 как высоту)
Чтобы устранить проблему, я просто изменил таблицу tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath и вернул по крайней мере 0,01 в качестве высоты строки.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
return rowModel.height + 0.01; // Add 0.01 to work around the crash issue.
}
он решил проблему для меня.
Ответ 7
Приложение вылетает из-за того, что вы внесли некоторые изменения в таблицуView. Либо вы добавили, либо удалили некоторые строки в tableView. Следовательно, когда контроллер представления запрашивает ваш класс контроллера модели для данных, в indexPaths есть несоответствие. Поскольку indexPaths изменились после модификации.
Итак, либо вы просто удалите вызов
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
или замените его на
[self.tableView reloadData];
Вызов reloadData проверяет количество секций, количество строк в каждом разделе и затем перезагружает все это.
Ответ 8
Вы должны проверить видимость ячейки перед перезагрузкой. Вот код Swift 3:
let indexPath = IndexPath(row: offset, section: 0)
let isVisible = tableView.indexPathsForVisibleRows?.contains{$0 == indexPath}
if let v = isVisible, v == true {
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Ответ 9
Сегодня я столкнулся с такой же проблемой, и решения здесь не работали для меня. Я решил это, вызвав [tableView reloadData]
перед методом анимации. Я использую Xcode 6.3 с iOS 8.3 sdk. Надеюсь, что это поможет
[tableView reloadData];
[tableView reloadRowsAtIndexPaths:indexArray
withRowAnimation:UITableViewRowAnimationBottom];