Не нарушено ли поведение NSFetchedResultsControllerDelegate «ChangeUpdate»? - PullRequest
10 голосов
/ 25 августа 2009

Документы для NSFetchedResultsControllerDelegate предоставляют следующий пример кода

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
            break;

    }

}

Когда я создаю новый NSManagedObject, NSFetchedResultsChangeInsert срабатывает (отлично!). Когда я изменяю значение атрибута (используется для заголовка ячейки), NSFetchedResultsChangeUpdate срабатывает. К сожалению, новый заголовок не отображается автоматически, если я не перезагружу таблицу, раздел или строку. Действительно, если новое имя приводит к тому, что результирующий набор сортируется по-другому, то NSFetchedResultsChangeMove срабатывает, и все в порядке, поскольку предоставленный код перезагружает весь раздел.

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

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

И да, если я запишу, что происходит, когда

[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 

вызывается для NSFetchedResultsChangeUpdate , он может извлечь последнее значение 'name' и установить его в textLabel ячейки. Имя просто не отображается в ячейке, пока я не перезагружу его. Даже если я просто нажму на ячейку, появится имя. Обратите внимание, что для воссоздания этого поведения вы должны создать новый управляемый объект, а затем дать ему имя, которое заставляет его сортировать FIRST в NSFetchedResultsController. Таким образом, NSFetchedResultsChangeMove не запускается (что работает, поскольку он перезагружает раздел).

Я что-то упустил или это ожидаемое поведение? «Обсуждение» reloadRowsAtIndexPaths заставляет меня поверить, что я должен иметь возможность просто установить textLabel ячейки без перезагрузки строки, раздела или таблицы.

Ответы [ 4 ]

3 голосов
/ 13 мая 2011

Вы должны вызвать [cell setNeedsLayout] или / и [cell setNeedsDisplay], чтобы обновить ячейку, в зависимости от реализации вашей ячейки.

Если вы составляете ячейку подпредставлений, как мы обычно делаем, вы полагаетесь на - layoutSubviews, поэтому вам следует позвонить [cell setNeedsLayout].

Если вы рисуете ячейку напрямую с помощью – drawRect:, вам следует позвонить [cell setNeedsDisplay].

Если вы используете как композицию, так и рисунок, вы должны вызвать оба.

1 голос
/ 09 февраля 2011

Хотя это явно не указано, вы должны убедиться, что вы включили методы делегатов для controllerWillChangeContent: и controllerDidChangeContent:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

и

- (void)controllerDidChangeContent:(BSFetchedResultsController *)controller {
    @try {
        [self.tableView endUpdates];
    }
    @catch (NSException * e) {
        NSLog(@"caught exception: %@: %@", [e name], [e description]);
    }
    @finally { }
}

NSFRC может запустить несколько контроллеров: didChangeObject: atIndexPath: forChangeType: newIndexPath: методы во время любого одного изменения, поэтому не ожидайте обновления строки таблицы сразу после каждого из них. Они будут обновляться только после того, как вы вызовете endUpdates для таблицы.

1 голос
/ 12 октября 2009

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

0 голосов
/ 21 апреля 2015

Вызов логики обновления пользовательского интерфейса в главном потоке решил мою проблему (оба [cell setNeedsLayout] & [cell setNeedsDisplay] не работают для меня):

...
case NSFetchedResultsChangeUpdate:
    dispatch_async(dispatch_get_main_queue(), {
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
    });
    break;
...

Более того (не об этой проблеме, но будет полезно), лучше использовать newIndexPath, если она доступна:

...
case NSFetchedResultsChangeUpdate:
    dispatch_async(dispatch_get_main_queue(), {
      NSIndexPath * targetIndexPath = (newIndexPath ?: indexPath)
      [self configureCell:[tableView cellForRowAtIndexPath:targetIndexPath]
              atIndexPath:targetIndexPath];
    });
    break;
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...