web-dev-qa-db-ja.com

一時的なNSManagedObjectインスタンスを処理する方法は?

NSManagedObjectインスタンスを作成し、それらを使用して、それらをゴミ箱に入れるか、sqlite dbに保存する必要があります。問題は、NSManagedObjectに接続されていないNSManagedObjectContextのインスタンスを作成できないことです。これは、dbのオブジェクトの一部が不要であると判断した後、何らかの方法でクリアする必要があることを意味します。

それに対処するために、同じコーディネーターを使用してインメモリストアを作成し、assignObject:toPersistentStore.を使用して一時オブジェクトをそこに配置しています。両方のストアのコンテキストから共通のものを取得しますか?または、そのようなタスクのために個別のコンテキストを作成する必要がありますか?


UPD:

今、私はインメモリストア用に別個のコンテキストを作成することを考えています。あるコンテキストから別のコンテキストにオブジェクトを移動するにはどうすればよいですか? [context insertObject:]を使用していますか?このセットアップでは問題なく動作しますか?オブジェクトのグラフから1つのオブジェクトを挿入すると、グラフ全体もコンテキストに挿入されますか?

85
fspirit

注:この答えはvery古いです。完全な履歴についてはコメントをご覧ください。その後私の推奨事項は変更され、関連付けられていないNSManagedObjectインスタンスの使用は推奨されなくなりました。私の現在の推奨事項は、一時的な子NSManagedObjectContextインスタンスを使用することです。

元の回答

これを行う最も簡単な方法は、NSManagedObjectを関連付けずにNSManagedObjectContextインスタンスを作成することです。

NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

次に、保存する場合:

[myMOC insertObject:unassociatedObject];
NSError *error = nil;
if (![myMoc save:&error]) {
  //Respond to the error
}
144
Marcus S. Zarra

iOS5は、マイクウェラーの答えに対するより単純な代替手段を提供します。代わりに、childNSManagedObjectContextを使用します。 NSNotificationCenterを介してトランポリンを使用する必要がなくなります

子コンテキストを作成するには:

NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
childContext.parentContext = myMangedObjectContext;

次に、子コンテキストを使用してオブジェクトを作成します。

NSManagedObject *o = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:childContext];

変更は、子コンテキストが保存されたときにのみ適用されます。したがって、変更を破棄するには、保存しないでください。

関係にはまだ制限があります。つまり、他のコンテキストのオブジェクトとの関係を作成することはできません。これを回避するには、objectIDを使用して、子コンテキストからオブジェクトを取得します。例えば。

NSManagedObjectID *mid = [myManagedObject objectID];
MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid];
object.relationship=mySafeManagedObject;

子コンテキストを保存すると、親コンテキストに変更が適用されます。親コンテキストを保存すると、変更が保持されます。

完全な説明については、 wwdc 2012セッション214 を参照してください。

39
railwayparade

Nilコンテキストから一時オブジェクトを作成することは、コンテキスト!= nil!を持つオブジェクトとの関係を実際に試行するまで正常に機能します。

それで大丈夫か確認してください。

9
user134611

この種のことを実現する正しい方法は、新しい管理対象オブジェクトコンテキストを使用することです。同じ永続ストアで管理オブジェクトコンテキストを作成します。

NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease];
[tempContext setPersistentStore:[originalContext persistentStore]];

次に、新しいオブジェクトを追加したり、変更したりします。

保存するときは、tempContextで[tempContext save:...]を呼び出し、保存通知を処理して元のコンテキストにマージする必要があります。オブジェクトを破棄するには、この一時的なコンテキストを解放して忘れてください。

したがって、一時的なコンテキストを保存すると、変更はストアに永続化され、それらの変更をメインコンテキストに戻すだけで済みます。

/* Called when the temp context is saved */
- (void)tempContextSaved:(NSNotification *)notification {
    /* Merge the changes into the original managed object context */
    [originalContext mergeChangesFromContextDidSaveNotification:notification];
}

// Here's where we do the save itself

// Add the notification handler
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(tempContextSaved:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:tempContext];

// Save
[tempContext save:NULL];
// Remove the handler again
[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:NSManagedObjectContextDidSaveNotification
                                              object:tempContext];

これは、マルチスレッドのコアデータ操作を処理する方法でもあります。スレッドごとに1つのコンテキスト。

この一時的なコンテキストから既存のオブジェクトにアクセスする必要がある場合(関係の追加など)、オブジェクトのIDを使用して次のような新しいインスタンスを取得する必要があります。

NSManagedObject *objectInOriginalContext = ...;
NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];

NSManagedObjectを間違ったコンテキストで使用しようとすると、保存中に例外が発生します。

9
Mike Weller

あなたが説明しているのは、まさにNSManagedObjectContextの目的です。

から コアデータプログラミングガイド:コアデータの基本

管理対象オブジェクトコンテキストは、インテリジェントなスクラッチパッドと考えることができます。永続ストアからオブジェクトをフェッチすると、一時コピーがスクラッチパッドに移動し、オブジェクトグラフ(またはオブジェクトグラフのコレクション)が形成されます。その後、これらのオブジェクトを自由に変更できます。ただし、実際にこれらの変更を保存しない限り、永続ストアは変更されません。

そして Core Data Programming Guide:Managed Object Validation

これは、管理オブジェクトコンテキストが「スクラッチパッド」を表すという考え方の基礎にもなります。一般に、管理オブジェクトをスクラッチパッドに移動して、最終的に変更をコミットまたは破棄する前に希望どおりに編集できます。

NSManagedObjectContextsは軽量になるように設計されています。それらを自由に作成および破棄できます。これは永続ストアコーディネーターであり、「重い」のは依存関係です。単一の永続ストアコーディネーターには、多くのコンテキストを関連付けることができます。古い、廃止されたスレッド制限モデルでは、これは各コンテキストで同じ永続ストアコーディネーターを設定することを意味します。今日では、ネストされたコンテキストを永続ストアコーディネーターに関連付けられているルートコンテキストに接続することを意味します。

コンテキストを作成し、そのコンテキスト内で管理対象オブジェクトを作成および変更します。それらを永続化し、それらの変更を伝えたい場合は、コンテキストを保存します。それ以外の場合は破棄します。

NSManagedObjectContextから独立した管理対象オブジェクトを作成しようとすると、トラブルが発生します。コアデータは、最終的にオブジェクトグラフの変更追跡メカニズムであることに注意してください。このため、管理対象オブジェクトは実際には 管理対象オブジェクトコンテキストの一部 です。コンテキスト ライフサイクルを観察 、および コンテキストなし 管理対象オブジェクトのすべての機能が正しく動作するわけではありません。

8
quellish

一時オブジェクトの使用に応じて、上記の推奨事項にいくつかの注意事項があります。私のユースケースは、一時オブジェクトを作成し、それをビューにバインドすることです。ユーザーがこのオブジェクトを保存することを選択した場合、既存のオブジェクトとの関係を設定して保存します。これらの値を保持する一時オブジェクトを作成しないようにするために、これを実行したいと思います。 (はい、ユーザーが保存してビューの内容を取得するまで待つことができますが、これらのビューをテーブル内に配置しているため、これを行うためのロジックはエレガントではありません。)

一時オブジェクトのオプションは次のとおりです。

1)(推奨)子コンテキストで一時オブジェクトを作成します。オブジェクトをUIにバインドしているため、子コンテキストでオブジェクトアクセサーが呼び出されることを保証できないため、これは機能しません。 (そうでないことを述べている文書を見つけていないので、仮定しなければなりません。)

2)オブジェクトコンテキストがnilの一時オブジェクトを作成します。これは機能せず、データの損失/破損が発生します。

私のソリューション:nilオブジェクトコンテキストで一時オブジェクトを作成することでこれを解決しましたが、オブジェクトを保存するとき、#2として挿入するのではなく、そのすべての属性をメインコンテキストで作成する新しいオブジェクトにコピーします。 NSManagedObjectサブクラスにcloneIntoという名前のサポートメソッドを作成しました。これにより、任意のオブジェクトの属性と関係を簡単にコピーできます。

6
greg

私にとって、マーカスの答えはうまくいきませんでした。ここに私のために働いたものがあります:

NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

次に、保存することにした場合:

[myMOC insertObject:unassociatedObjet];
NSError *error = nil;
[myMoc save:&error];
//Check the error!

また、リリースすることを忘れてはいけません

[unassociatedObject release]
1
Lucas

私はこれを書き直しています answer for Swift Swiftこの質問にリダイレクトします。

次のコードを使用して、ManagedContextなしでオブジェクトを宣言できます。

let entity = NSEntityDescription.entity(forEntityName: "EntityName", in: myContext)
let unassociatedObject = NSManagedObject.init(entity: entity!, insertInto: nil)

後で、オブジェクトを保存するには、それをコンテキストに挿入して保存します。

myContext.insert(unassociatedObject)
// Saving the object
do {
    try self.stack.saveContext()
    } catch {
        print("save unsuccessful")
    }
}
0
Mitul Jindal