0

更新:有时我会收到错误消息

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和调用 performFetch。然后我附上以典型方式获取数据的数据源(我只有一个部分)nilsectionNameKeyPathNSFetchedResultsController

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

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

到目前为止一切顺利,我可以看到我的对象从数据库中拉出。这个想法是用户立即看到持久化的东西,直到新数据来自网络。

然后,在performBlock后台内部ManagedObjectContext(以主 UI ManagedObjectContext 作为父级)执行网络获取,将对象转换为核心数据并将它们推送到主 UI 上下文。这也可以。

NSFetchResultsController当开始收到有关新对象到达的通知时,麻烦就开始了。我有一个典型的样板文件,在几本书和苹果自己的文档中都有提到:

- (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。它似乎是不确定的(我的fetchLimitbatchSize设置为 20)

此外,当insertRowsAtIndexPath被调用时,断言是从可可层抛出的:

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

不,没有进一步的解释。是不是很了不起?

我认为 UITableView 期望和实际获得的行数或部分数之间存在一些不一致。有什么建议我应该怎么看?如果没有 UITableView 源代码,我不知道从哪里开始寻找。目前我很想重新实现NSFetchedResultsController自己的模拟,以便我可以看到实际发生的事情。

4

1 回答 1

1

did you implement the other delegate methods for the NSFetchedResultController?

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

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
  switch(type) {
    case NSFetchedResultsChangeInsert:
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
      break;
    case NSFetchedResultsChangeDelete:
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                    withRowAnimation:UITableViewRowAnimationFade]; break;
  }
}
于 2013-03-26T09:18:04.660 回答