Строка не движется при изменении модели с NSFetchResultsController

Я работаю над своим первым приложением для iPhone (базовое приложение со списком дел) и только что добавил NSFetchResultsController в мое табличное представление. У меня есть 2 секции строк, и у меня нет проблем с добавлением строк, и они отсортированы по тому, является ли атрибут завершенной цели истинным - если это так, то он переходит в нижнюю секцию и вычеркивается.

И всякий раз, когда вы проводите пальцем вправо по строке в верхнем разделе, он изменяет полный атрибут цели на true и перемещает его в нижний раздел:

  RegimenGoal *goal = [_fetchedResultsController objectAtIndexPath:swipedIndexPath];
  goal.completed = [NSNumber numberWithBool:YES];

  [context save:&error];

Вот мой код контроллера представления.

По какой-то причине это работает только для целей, которые я только что создал, но не работает для существующих целей, которые я добавил. После некоторой отладки я понял, что NSFetchedResultsChangeMove не запускается, вместо этого NSFetchedResultsChangeUpdate - всякий раз, когда я делаю это действие для существующих целей, которые не являются новыми.

Об этом я также узнал в документации Apple: "Перемещенные объекты иногда сообщаются как обновленные". И я попробовал обходное решение, перечисленное там, просто проверив, является ли завершенный атрибут истинным или нет.

И когда я это делаю, я вижу, что newIndexPath не новый - это просто старый indexPath, и это вводит меня в заблуждение... есть идеи о том, почему это происходит?

1 ответ

Решение

Произошла ошибка при создании контроллера выбранных результатов. Если вы группируете результаты по разделам, указав sectionNameKeyPath:@"completed", затем вы должны добавить дескриптор первой сортировки, используя тот же ключ:

NSSortDescriptor *completeSort = [[NSSortDescriptor alloc] initWithKey:@"completed" ascending:YES];
NSSortDescriptor *daySort = [[NSSortDescriptor alloc] initWithKey:@"dateCreated" ascending:YES];
[dayRequest setSortDescriptors:[NSArray arrayWithObjects:completeSort, daySort, nil]];

Еще одна проблема в tableView:cellForRowAtIndexPath:

[self configureCell:cell atIndexPath:indexPath];
[cell formatCell:indexPath.section];

Здесь вы предполагаете, что раздел 0 содержит все элементы с completed = NO и раздел 1 содержит все элементы с completed = YES, Но если все элементы выполнены, то есть только один раздел (раздел 0), содержащий все выполненные элементы. Таким образом, вы не можете использовать indexPath.section в качестве аргумента formatCell, Вы должны использовать значение goal.completed вместо. Например, вы можете переместить formatCell позвонить в configureCell:atIndexPath: метод:

- (void)configureCell:(RegimenCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    RegimenGoal *goal = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.label.text = goal.text;
    [cell formatCell:goal.completed.intValue];
}

И теперь нет смысла делать ячейку таблицы reuseIdentifier зависит от раздела и номера строки. Я думаю, что вы можете просто заменить

NSString *CellIdentifier = [NSString stringWithFormat:@"%d-%d", indexPath.row, indexPath.section];

фиксированной строкой

NSString *CellIdentifier = @"YourCellIdentifer";

Аналогичная проблема заключается в setNavTitle метод:

int goalsCount = [_tableView numberOfRowsInSection:0];
int completedCount = [_tableView numberOfRowsInSection:1];

Опять же, если все цели достигнуты, они все находятся в разделе 0, и в нем нет раздела 1. Ваш текущий код будет отображать "(0%)" в этом случае вместо "(100%)".

Дальнейшие замечания:

  • Обходной путь "Перемещенные объекты иногда сообщается как обновленный" здесь не нужен.
  • Для NSFetchedResultsChangeUpdate событие, вы можете позвонить либо [self configureCell:...] или же [[_tableView reloadRowsAtIndexPaths:...], Звонить обоим не обязательно.
  • Переменная экземпляра _fetchedResultsController следует использовать только в fetchedResultsController метод, который создает выбранный контроллер результатов (FRC) по требованию. Во всех других местах вы должны использовать self.fetchedResultsController чтобы убедиться, что FRC создан в случае необходимости.
Другие вопросы по тегам