web-dev-qa-db-ja.com

NSManagedObjectを挿入せずにインスタンス化する方法はありますか?

トランザクションを挿入するユーザーインターフェイスがあります。ユーザーがプラスをクリックすると画面が表示され、Core Data NSManagedObjectエンティティをインスタンス化してユーザーが作業できるようにします。次に、ユーザーが[保存]ボタンをクリックすると、保存機能が呼び出されます。

コードまで:

transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext];
//even if i dont call save: its going to show up on my table
[self.managedObjectContext save:&error]

P.S私はそのテーブルでNSFe​​tchedResultsControllerを使用していますが、NSFetchedResultsControllerがセクションとオブジェクトをテーブルに挿入していることがわかります。

私の考えは、トランザクションNSManagedObjectをインスタンス化する方法があれば、クライアントが選択するまで保存せずに更新できるということです。

54
Edward Ashak

Nil MOCの使用には根本的な問題があります。異なるMOCのオブジェクトは相互に参照することは想定されていません。これはおそらく、関係の片側にnil MOCがある場合にも当てはまります。保存するとどうなりますか? (アプリの別の部分を保存するとどうなりますか?)

オブジェクトにリレーションシップがない場合、できることがたくさんあります(NSCodingなど)。

NSPredicateで-[NSManagedObject isInserted]を使用できる場合があります(おそらく、挿入してから正常に保存するまでの間はYESです)。または、同じ動作の一時的なプロパティを使用できます(awakeFromInsertでYESに、willSaveでNOに設定します)。アプリの別の部分を保存すると、これらの両方に問題が生じる可能性があります。

ただし、2番目のMOCを使用することで、CoreDataの使用が「想定」されます。自動的に競合の検出と解決を処理します。もちろん、変更があるたびに新しいMOCを作成する必要はありません。 UIの一部で他の部分に保存されていない変更が表示されることを気にしない場合は、低速の「ユーザースレッド」による未保存の変更に対して1つのMOCを使用することが賢明です(MOC間通信のオーバーヘッドは無視できます)。

17
tc.

価値のあることとして、Marcus Zarraはnilコンテキストアプローチを推進しており、新しいコンテキストを作成するには費用がかかると主張しています。詳細については、同様の質問について this answer を参照してください。

更新

私は現在、nilコンテキストアプローチを使用していますが、他の人にとって興味深いものに遭遇しました。コンテキストなしで管理対象オブジェクトを作成するには、initWithEntity:insertIntoManagedObjectContext:NSManagedObjectのメソッド。この方法に関するAppleのドキュメントによると:

contextnilでない場合、このメソッドは[context insertObject:self](これにより、awakeFromInsertが呼び出されます)。

ここでの意味は重要です。管理対象オブジェクトの作成時にnilコンテキストを使用すると、insertObject:が呼び出されないため、awakeFromInsertが呼び出されなくなります。そのため、awakeFromInsertコンテキストを使用する場合、nilで行われるオブジェクトの初期化またはデフォルトプロパティ値の設定は自動的に行われません。

結論:コンテキストなしで管理対象オブジェクトを使用する場合、awakeFromInsertは自動的に呼び出されず、補正のために追加のコードが必要になる場合があります。

37

ここに私がそれを解決した方法があります:

ロード時に、新しいトランザクションを処理していることがわかっている場合、コンテキスト外のトランザクションを作成しました。

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext];
        transaction = (Transaction *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

それから関係船を確立することになると、私はこれをしました:

if( transaction.managedObjectContext == nil){
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext];
        Category *category = (Category *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
        category.title = ((Category *)obj).title;
        transaction.category = category;
        [category release];
    }
    else {
        transaction.category = (Category *)obj;
    }

そして最後に保存する:

if (transaction.managedObjectContext == nil) {
        [self.managedObjectContext insertObject:transaction.category];
        [self.managedObjectContext insertObject:transaction];
    }
    //NSLog(@"\n saving transaction\n%@", self.transaction);

    NSError *error;
    if (![self.managedObjectContext save:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
19
Edward Ashak

-[NSManagedObject initWithEntity:insertIntoManagedObjectContext:]NSManagedObjectContextを挿入し、管理対象オブジェクトコンテキストにnilを渡すことができます。もちろん、それをコンテキストに割り当てる必要があります(保存する前に-[NSManageObjectContext insertObject:]を使用します。これは、私が知る限り、実際にはCore Dataの意図したパターンではありません(ただし、@ mzarraの答え here )。いくつかのトリッキーな順序の問題があります(つまり、インスタンスがコンテキストを持つことを予期する前にインスタンスがコンテキストに割り当てられるようにするなど)。より標準的なパターンは、新しい管理オブジェクトコンテキストを作成し、新しいオブジェクトをそのコンテキストに保存します。ユーザーが保存してコンテキストを保存し、NSManagedObjectDidSaveNotificationを処理して変更を「メイン」コンテキストにマージします。ユーザーがトランザクションをキャンセルした場合、コンテキストを吹き飛ばして続行しますあなたのビジネスで。

8
Barry Wark

NSManagedObjectは、nilをコンテキストとして使用して作成できますが、他のNSManagedObjectsにリンクする必要がある場合は、エラーになります。その方法で、コンテキストを宛先画面に渡し、その画面でNSManagedObjectを作成します。すべての変更を他のNSManagedObjectsにリンクさせます。ユーザーがキャンセルボタンをタップした場合、NSManagedObjectを削除してコンテキストを保存します。ユーザーが[保存]ボタンをタップすると、NSManagedObjectのデータを更新し、コンテキストに保存して、画面を解放します。ソース画面で、リロードでテーブルを更新します。

宛先画面でNSManagedObjectを削除すると、コアデータにファイルを更新する時間が与えられます。これは通常、Tableviewの変更を表示しないための十分な時間です。 iPhoneカレンダーアプリでは、保存されてからテーブルビューに表示されるまでに遅延があります。これは、ユーザーが追加されたばかりの行に集中するというUIの観点からは良いことと考えることができます。これがお役に立てば幸いです。

2
ejkujan