Подтвердить что ты не робот

ReloadRowsAtIndexPaths: withRowAnimation: сбой моего приложения

У меня возникла странная проблема с моим UITableView: я использую reloadRowsAtIndexPaths:withRowAnimation: для перезагрузки некоторых определенных строк, но приложение выходит из строя с кажущимся несвязанным исключением: NSInternalInconsistencyException - Попытка удалить больше строк, чем существует в разделе.

Мой код выглядит следующим образом:

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

Когда я заменяю это сообщение reloadRowsAtIndexPaths:withRowAnimation: простым reloadData, он отлично работает.

Любые идеи?

4b9b3361

Ответ 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];