reloadRowsAtIndexPaths: withRowAnimation: вылетает мое приложение - PullRequest
18 голосов
/ 16 декабря 2010

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

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

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

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

Есть идеи?

Ответы [ 8 ]

28 голосов
/ 18 октября 2011

Проблема в том, что вы, возможно, изменили размер вашей таблицы.Например, вы должны добавить или удалить некоторые исходные данные для табличного представления.

В этом случае, когда вы вызываете reloadData, ваша таблица полностью перезагружается, включая размеры разделов и количество этих разделов.

Но когда вы вызываете reloadRowsAtIndexPaths:withRowAnimation:, эти параметры вашего табличного представленияне перезагружаются.Это вызывает следующую проблему: когда вы пытаетесь перезагрузить некоторую таблицу ячеек, проверьте размер табличного представления и увидите, что он был изменен.Это приводит к аварии.Этот метод можно использовать только тогда, когда вы не хотите перезагружать представление ячейки (например, метка изменилась или вы хотите изменить ее размер).

Теперь, если вы хотите удалить / добавить ячейки из /к табличному представлению следует использовать следующий подход:

  1. Сообщите таблице, что ее размер будет изменен, вызвав метод beginUpdates из UITableView
  2. Сообщите о вставке новой строки (строк)используя метод - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  3. Сообщите об удалении строк, используя метод - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  4. Сообщите таблице, что ее размер был изменен, вызвав метод endUpdates из UITableView

Надеюсь, это будет полезно

9 голосов
/ 18 октября 2011

Я думаю, что следующий код может работать:

[self.tableView beginUpdates];

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

[self.tableView endUpdates];
5 голосов
/ 07 февраля 2016

У меня была эта проблема, которая была вызвана блоком, вызывающим reloadRowsAtIndexPaths: withRowAnimation: и параллельным потоком, вызывающим reloadData.Сбой произошел из-за reloadRowsAtIndexPaths: withRowAnimation нашла пустую таблицу, даже если бы я проверил исправность numberOfRowsInSection & numberOfSections.

Я решил, что мне все равно, вызывает ли это исключение.Визуальное искажение, с которым я мог бы жить как пользователь приложения, а не с этим целым приложением.

Вот мое решение, которым я с удовольствием поделюсь и приветствовал бы конструктивную критику.Если есть лучшее решение, я бы хотел услышать его?

- (void) safeCellUpdate: (NSUInteger) section withRow : (NSUInteger) row {
    // It's 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's just to refresh the view and if an exception occurs it's most likely that that is what's happening in parallel.
            // Nothing needs done
            return;
        }
    });
}
1 голос
/ 12 июля 2017

Вы должны проверить видимость ячейки перед перезагрузкой.Вот код 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)
        }
1 голос
/ 08 октября 2016

После многих попыток я обнаружил, что «reloadRowsAtIndexPaths» можно использовать только в определенных местах, только если изменить содержимое ячейки, а не вставить или удалить ячейки.Ни одно место не может использовать его, даже если вы завернули его в

[self beginUpdates];
//reloadRowsAtIndexPaths
[self endUpdates];

Я нашел места, которые могут его использовать:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath - (IBAction) unwindToMealList: (UIStoryboardSegue *) sender

Любая попытка другоготакие места, как вызов его из «viewDidLoad» или «viewDidAppear», либо не вступят в силу (для загруженной ячейки, я имею в виду, перезагрузка не вступит в силу), либо вызовут исключение.

Поэтому попробуйте использовать «reloadRowsAtIndexPaths»только в тех местах.

1 голос
/ 13 декабря 2012

ЭТО СТАРЫЙ.НЕ ИСПОЛЬЗОВАТЬ.Я только столкнулся с этой проблемой, когда я звонил 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];
0 голосов
/ 30 мая 2017

Приложение вылетает, потому что вы внесли некоторые изменения в свой tableView. Вы добавили или удалили несколько строк в tableView. Следовательно, когда контроллер представления запрашивает данные у вашего контроллера модели, происходит несоответствие в indexPaths. Поскольку indexPath изменились после модификации.

Так что либо вы просто удалите звонок

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

или замените его на

[self.tableView reloadData];

Вызов reloadData проверяет ваше количество разделов, количество строк в каждом разделе и затем перезагружает все это.

0 голосов
/ 29 января 2016

У меня была такая же проблема. В моем случае; это происходило только в том случае, если другой контроллер представления вставлял / выдвигал существующий контроллер представления таблицы, а затем вызывалась функция [self.tableView reloadRowsAtIndexPaths].

Вызов reloadRowsAtIndexPaths скрывал / отображал разные строки в табличном представлении, в котором более 30 визуально сложных строк. Когда я попытался исправить проблему, я обнаружил, что если я слегка прокручиваю приложение, то табличное представление не падает. Кроме того, это не было сбой, если я не скрываю ячейку (возвращая 0 в качестве высоты)

Чтобы решить эту проблему, я просто изменил функцию "(CGFloat) 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.
}

это решило проблему для меня.

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