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[オフトピック:それはかなり典型的だと思うかもしれませんが、それを行うには少なくとも20の方法があることがわかります...]

viewDidLoadの場合、小さな制限が固定され、オフセットが0で、バッチサイズが固定されたフェッチリクエストを作成します。キャッシュ名とperformFetchを呼び出してNSFetchedResultsController、そのリクエストでを開始します。次に、通常の方法でデータを取得するデータソースを添付します(セクションは1つしかありません)nilnilsectionNameKeyPathNSFetchedResultsController

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

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

これまでのところ、オブジェクトがDBから引き出されているのを見ることができます。アイデアは、新しいデータがネットワークから来るまで、ユーザーは永続的なものをすぐに見るということです。

performBlock次に、バックグラウンド(メインUI ManagedObjectContextを親として持つ)の内部で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の場合もあります。非決定論的であるように見えます(私の場合fetchLimitbatchSize20に設定されています)

さらに、insertRowsAtIndexPathが呼び出されると、アサーションはココアレイヤーからスローされます。

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

いいえ、これ以上の説明はありません。素晴らしいですね。

UITableViewが期待し、実際に取得する行またはセクションの数には、いくつかの矛盾があると思います。どのように見るべきか提案はありますか?UITableViewのソースコードがないと、どこから探し始めるのかわかりません。NSFetchedResultsController現在、実際に何が起こっているのかを確認できるように、自分のアナログを再実装したいと思っています。

4

1 に答える 1

1

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 に答える