2013-03-26 4 views
0

Update: иногда я получаю сообщение об ошибкеотказ Assertion в UITableView 1070

2013-03-27 19:23:23.094 *** Assertion failure in -[TableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:1070 

2013-03-27 19:23:31.280 [53301:c07] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (4) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null) 
2013-03-27 19:23:31.281 [53301:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (4) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' 

У меня есть приложение, которое извлекает большинство из его данных из удаленного сервиса, и сохраняется его с использованием основных данных. Я пишу вид, который показывает коллекцию объектов в UITableView с бесконечной прокрутки [Offtopic: Можно было бы подумать, что это довольно типично, но оказывается, есть, по крайней мере 20 способов сделать это ...]

В моем viewDidLoad Я строю запрос на выборку с фиксированным малым пределом, смещением 0 и фиксированным размером партии. Я инициирую NSFetchedResultsController с этим запросом nil для имени кеша и nil для sectionNameKeyPath и вызовите функцию executeFetch. Затем я придаю источник данных, который принимает данные от NSFetchedResultsController в типичном пути (я только когда-либо один раздел)

- (NSInteger) tableView:(UITableView *)tableView 
    numberOfRowsInSection:(NSInteger)section 
{ 
    return [[fetchController.resultsController sections][section] 
      numberOfObjects]; 
} 

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 1; 
} 

До сих пор так хорошо, что я могу видеть мои объекты вытащил из БД. Идея заключается в том, что пользователь сразу же видит сохраняющиеся вещи, пока новые данные не поступят из сети.

Затем, внутри performBlock на фоне ManagedObjectContext (у которого есть основной пользовательский интерфейс ManagedObjectContext как родительский элемент) Я выполняю сетевую выборку, преобразую объекты в основные данные и перетаскиваю их в основной контекст интерфейса. Это хорошо работает.

Неисправность начинается, когда NSFetchResultsController начинает получать уведомления о прибывающих новых объектах. У меня есть типичный шаблонного, который упоминается в нескольких книгах и в собственной документации Apple:

- (void)controller:(NSFetchedResultsController*)controller 
didChangeObject:(id)anObject 
atIndexPath:(NSIndexPath*)indexPath 
forChangeType:(NSFetchedResultsChangeType)type 
newIndexPath:(NSIndexPath*)newIndexPath 
{ 
    switch(type) { 
     case NSFetchedResultsChangeInsert: 
      [self.table insertRowsAtIndexPaths:@[newIndexPath] 
         withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     case NSFetchedResultsChangeDelete: 
      [self.table deleteRowsAtIndexPaths:@[indexPath] 
         withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     case NSFetchedResultsChangeUpdate: 
      [self.delegate 
      populateCell:[self.table cellForRowAtIndexPath:indexPath] 
      indexPath:indexPath 
      ]; 
      break; 
     case NSFetchedResultsChangeMove: 
      [self.table deleteRowsAtIndexPaths:@[indexPath] 
         withRowAnimation:UITableViewRowAnimationFade]; 
      [self.table insertRowsAtIndexPaths:@[newIndexPath] 
         withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

Теперь вещи начинают получать странно. Во-первых, newIndexPath я получаю странно: иногда это 0, иногда 18, иногда 28. Это, кажется, не детерминированной (мой fetchLimit и batchSize установлены 20)

Кроме того, когда insertRowsAtIndexPath называется утверждение выбрасывается из слоя какао:

*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070 

Нет, дальнейших объяснений нет. Разве это не чудесно?

Я предполагаю, что существует некоторая несогласованность между количеством строк или разделов, которые UITableView ожидает и фактически получает. Есть ли какие-либо предложения, каким образом я должен смотреть? Без исходного кода UITableView я понятия не имею, с чего начать искать. В настоящее время я испытываю соблазн повторно реализовать аналог NSFetchedResultsController, чтобы я мог видеть, что происходит на самом деле.

+0

Я просто наткнулся на это. Похоже на эту проблему, которую я только что нашел и исправил: http://stackoverflow.com/questions/16905935/assertion-failure-in-uitableview-endcellanimationswithcontext-with-nsfetche/16905936#16905936 – Peyman

ответ

1

Вы реализовали другие методы делегата для NSFetchedResultController?

+0

Да, конечно, я это сделал. Я не опубликовал весь свой исходный код, поскольку это слишком сложно сделать, не публикуя все мое приложение. –

+0

ОК, и вы уверены, что вызываете «didChangeObject» в основном потоке? Вот фрагмент: if (! [NSThread isMainThread]) { NSLog (@ "не на основной теме"); } – CarlJ

+0

Что вы подразумеваете под звонком?Предполагаю, вы имеете в виду метод делегата? Да, это называется основной нитью. Уведомления отправляются ManagedObjectContext, который привязан к основному потоку пользовательского интерфейса. –

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