2009-08-25 4 views
10

Документов для NSFetchedResultsControllerDelegate предоставить следующий кодЯвляется ли NSFetchedResultsControllerDelegate 'ChangeUpdate' нарушенным?

- (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, он может получить последнее значение «имя» и установить его в TextLabel клетки , Это имя просто не отображается в ячейке, если я не перезагружу его. Даже если я просто щелкнул по ячейке, появится имя. Обратите внимание, что для воссоздания этого поведения вы должны создать новый управляемый объект, а затем дать ему имя, которое заставляет его сортировать FIRST в NSFetchedResultsController. Таким образом, NSFetchedResultsChangeMove не срабатывает (что работает, так как он перезагружает раздел).

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

+0

Это должно быть wo очий. Я делаю то же самое. Для изменения атрибутов при вызове save: выходят уведомления MOC. NSFetchedResultsController видит это изменение и вызывает мой метод configureCell: atIndexPath. Там я захватываю значения и заполняю ячейку, и ячейка обновляется немедленно. Отправьте свой код configureCell. –

ответ

3

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

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

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

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

1

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

+0

На этом этапе - что является лучшим способом получить ячейку, которая находится на экране? tableview: cellForRowAtIndexPath: создает новую ячейку, тогда как я хочу получить ссылку на ячейку на экране ... правильно? –

+0

Как правило, нет необходимости, для любой ячейки, которую вы настраиваете, вы можете вызвать setNeedsDisplay. Если это новая ячейка, у нее нет кеша, поэтому не беспокойтесь, если вы переконфигурируете, она будет перерисовываться. Однако, если вы действительно хотите знать, какие экраны видны, взгляните на мой ответ на: http://stackoverflow.com/questions/996515/getting-visible-cell-from-uitableview-pagingenabled/1566432#1566432 –

1

Хотя это не было явно указано, вы на самом деле есть, чтобы убедиться, что вы включили методы делегата для 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 в таблице.

0

Вызов UI логику обновления в основной поток решить мою проблему (оба [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; 
... 
+1

те события уже находятся в главном потоке, то, что вы делаете, это шунтирование к следующему циклу событий, хотя GCD не на 100% хорош в этом, выполнение после задержек является более надежным. – malhal

+0

@malhal хороший пункт. – Kjuly

Смежные вопросы