-1

iPhone アプリで親子 Core Data 関係を設定しています。Manufacturer オブジェクトと Car オブジェクトがあります。これは、メーカーが所有者である対多の関係です。メイン ビューは、メーカーを含むテーブル ビューです。詳細ビューは、さまざまな種類の車を含む別のテーブル ビューです。私はTim Roadley の Core Data Tutorialをベースとして使用しています。このチュートリアルでは、テーブル ビューにStanford の Core Data Table View Libraryを使用します。

車とメーカーを追加しても問題はありませんが、テーブルビューで複数の車を削除すると、次のエラーが発生します。

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

2012-07-29 23:39:33.561 アプリ [16368:c07] *キャッチされない例外 'NSInternalInconsistencyException' が原因でアプリを終了しています。理由: '無効な更新: セクション 0 の行数が無効です。既存のセクションに含まれる行数更新後 (0) は、更新前にそのセクションに含まれていた行数 (2) に、そのセクションから挿入または削除された行数 (0 挿入、1 削除) をプラスまたはマイナスし、プラスまたはマイナスそのセクションに移動した、またはそのセクションから移動した行数 (移動した行数 0、移動した行数 0)。

唯一の車を削除すると、次のエラーが発生したときに新しい車を追加しようとするまで問題なく動作します。

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'manufacturer' between objects in different contexts (source = <Car: 0x6d96da0> (entity: Car; id: 0x6d8a3c0 <x-coredata:///Car/tC78E17EB-1D68-4998-8C4D-6D1199CE253F4> ; data: {
dateAdded = nil;
manufacturer = nil;
carName = new;
}) , destination = <Manufacturer: 0x6bb1f40> (entity: Manufacturer; id: 0x6d87340 <x-coredata://2E8DDF34-B01A-4203-A53E-73DBE6A2F976/Garden/p6> ; data: <fault>))'

これが私の編集方法です:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{

if (editingStyle == UITableViewCellEditingStyleDelete) {

    [self.tableView beginUpdates];

    Plant *plantToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSLog(@"Deleting plant '%@'", plantToDelete.plantName);
    [self.managedObjectContext deleteObject:plantToDelete];
    [self.managedObjectContext save:nil];

    //delete empty tableview row
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
    NSLog(@"Before performFetch...");
    [self performFetch];
    NSLog(@"After performFetch...");

    [self.tableView endUpdates];
}
}

このperformFetchメソッドは、前述のCoreDataTableViewControllerファイルに含まれています。あなたの便宜のために、ここにそれがあります:

(void)performFetch
{
_debug = YES;

if (self.fetchedResultsController) {
    if (self.fetchedResultsController.fetchRequest.predicate) {
        if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate);
    } else {
        if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName);
    }
    NSError *error;
    [self.fetchedResultsController performFetch:&error];
    if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
} else {
    if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
[self.tableView reloadData];

}

他の質問によると、私は and を使用してこれを正しく行っていbeginUpdatesますendUpdates。これは不可解なエラーです。ご協力いただきありがとうございます。

4

3 に答える 3

1

オブジェクトがコンテキストから削除された場合、フェッチされた結果コントローラーはその変更を既に認識しています。あなたが抱えている主な問題は、テーブルへの更新を処理している最中に perform fetch を呼び出すことだと思います。その行をコメントアウトしても、まだエラーがありますか?

さらに、以下は問題の別の部分である場合とそうでない場合があります。これは、自分のコードと異なる場合です。

tableView:CommitEditingStyle: で begin/end edits 呼び出しを見たことがありません。そのメソッドの私自身のプロセスは、通常、テーブルの行を気にせずにオブジェクトを削除します。テーブルの行は、次のように fetchedResultController デリゲート メソッドで調整されます。

   -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    //the fetch controller is about to start sending change notifications so prepare the tableview
    [self.tableView beginUpdates];
}


-(void)controller:(NSFetchedResultsController *)controller 
  didChangeObject:(id)anObject 
      atIndexPath:(NSIndexPath *)indexPath 
    forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath {

    // reconcile your rows here
    switch(type) {
     case NSFetchedResultsChangeInsert:

       break;

     case NSFetchedResultsChangeDelete:
       // this one is you
       [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
       break;

     case NSFetchedResultsChangeUpdate:

       break;

     case NSFetchedResultsChangeMove:

       break;
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}

結局、行数がフェッチされたオブジェクトの数と一致する限り、そのエラーは発生しません。

于 2012-07-30T04:40:09.830 に答える
0

Tim Roadley の CoreDataTableViewController のサブクラスである tableViewController を開くと、同じエラーが発生していました。私の特定のアプリでは、ユーザーが行を追加または削除できる必要はありませんが、取得した結果を名前と距離で並べ替えたり、データを検索したりできます。私は Dean David の回答 (上記の受け入れられた回答) を使用しましたが、すべての case ステートメントの後に、break ステートメントのみを追加しました。これまでのところ、このアプリではうまくいきました!

于 2014-08-15T17:13:35.450 に答える