更新:エラーメッセージが表示されることがあります
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つしかありません)nil
nil
sectionNameKeyPath
NSFetchedResultsController
- (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の場合もあります。非決定論的であるように見えます(私の場合fetchLimit
はbatchSize
20に設定されています)
さらに、insertRowsAtIndexPath
が呼び出されると、アサーションはココアレイヤーからスローされます。
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
いいえ、これ以上の説明はありません。素晴らしいですね。
UITableViewが期待し、実際に取得する行またはセクションの数には、いくつかの矛盾があると思います。どのように見るべきか提案はありますか?UITableViewのソースコードがないと、どこから探し始めるのかわかりません。NSFetchedResultsController
現在、実際に何が起こっているのかを確認できるように、自分のアナログを再実装したいと思っています。