55

私は、かなり標準的なセットアップであると想定しています。1つのスクラッチパッドMOCは決して保存されず(Webからダウンロードされたオブジェクトの束を含む)、もう1つの永続的なMOCはオブジェクトを永続化します。ユーザーがscratchMOCからオブジェクトを選択してライブラリに追加する場合、1)オブジェクトをscratchMOCから削除してpermanentMOCに挿入するか、2)オブジェクトをpermanentMOCにコピーします。Core Data FAQには、次のようなオブジェクトをコピーできると書かれています。

NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *copy = [context2 objectWithID:objectID];

(この場合、context2はpermanentMOCになります。)ただし、これを行うと、コピーされたオブジェクトに障害が発生します。データは最初は未解決です。後で解決されると、すべての値がnilになります。元のmanagedObjectのデータ(属性または関係)は、実際にはコピーまたは参照されません。したがって、このobjectWithID:メソッドを使用することと、insertNewObjectForEntityForName:を使用して完全に新しいオブジェクトをpermanentMOCに挿入することの違いはわかりません。

パーマネントMOCで新しいオブジェクトを作成し、古いオブジェクトから各キーと値のペアを手動でコピーできることはわかっていますが、そのソリューションにはあまり満足していません。(私はこの問題を抱えているさまざまな管理対象オブジェクトをいくつか持っているので、コピーを作成して更新する必要はありません。開発を続けるにつれて、それらすべてのメソッドを作成します。)より良い方法はありますか?

4

5 に答える 5

56

まず、NSManagedObjectContext単一のスレッドに複数あることは標準構成ではありません。99%の場合、必要なコンテキストは1つだけであり、それによってこの状況が解決されます。

なぜあなたはあなたが複数を必要とすると感じますNSManagedObjectContextか?

アップデート

これは、実際には、それが理にかなっているところで私が見た数少ないユースケースの1つです。これを行うには、あるコンテキストから別のコンテキストへのオブジェクトの再帰コピーを実行する必要があります。ワークフローは次のようになります。

  1. 永続的なコンテキストで新しいオブジェクトを作成する
  2. ソースオブジェクトから属性のディクショナリを取得します(これを行うには、を使用-dictionaryWithValuesForKeys-[NSEntityDescription attributesByName]ます。
  3. 値のディクショナリをターゲットオブジェクトに設定します(を使用して-setValuesForKeysWithDictionary
  4. 関係がある場合は、このコピーを再帰的に実行し、ハードコードされた(循環ロジックを回避するため)か、またはを使用して関係をウォークする必要があります。-[NSEntityDescription relationshipsByName]

別の人が述べたように、 The Pragmatic Programmers Core Data Bookの私の本からサンプルコードをダウンロードして、この問題の1つの解決策を見ることができます。もちろん、本の中で私はそれをより深く議論します:)

于 2010-06-09T17:54:10.010 に答える
10

ドキュメントは誤解を招き、不完全です。objectIDメソッド自体はオブジェクトをコピーするのではなく、必要な特定のオブジェクトを取得したことを保証するだけです。

このcontext2例のは、実際にはソースコンテキストであり、宛先ではありません。宛先コンテキストにそのIDを持つオブジェクトがないため、nilを取得しています。

オブジェクトグラフの複雑さとコンテキストがグラフを管理する方法のため、管理対象オブジェクトのコピーはかなり複雑です。コピーしたオブジェクトを新しいコンテキストで詳細に再作成する必要があります。

これは、 The Pragmatic Programmer's Core Data:MacOSXでデータを永続化するためのAppleのAPIのサンプルコードから抜粋したサンプルコードです。(Pragmaticサイトで本を購入しなくても、プロジェクトコード全体をダウンロードできる場合があります。)コンテキスト間でオブジェクトをコピーする方法の大まかなアイデアが得られるはずです。

オブジェクトをコピーする基本コードを作成できますが、各オブジェクトグラフの関係の詳細は、通常、データモデルごとにカスタマイズする必要があることを意味します。

于 2010-06-08T16:41:54.910 に答える
7

私自身も同じ問題を抱えていて、後でコンテキストに追加できる、作成された切断されたエンティティに関するこの記事を見つけました:http: //locassa.com/temporary-storage-in-apples-coredata/

データベースにオブジェクトを格納するため、NSManagedObjectがあるという考え方です。私のハードルは、これらのオブジェクトの多くがHTTP APIを介してダウンロードされ、セッションの最後にそれらのほとんどを破棄したいということでした。ユーザー投稿のストリームを考えてみてください。お気に入りに追加されたもの、または下書きとして保存されたものだけを保存したいと思います。

を使用してすべての投稿を作成します

+ (id)newPost {
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:self.managedObjectContext];
    Post *post = [[Post alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
    return post;
}

次に、投稿がお気に入りに追加されると、ローカルの管理対象オブジェクトコンテキストに挿入されます

+ (BOOL)favoritePost:(Post *)post isFavorite:(BOOL)isFavorite
{
    // Set the post's isFavorite flag
    post.isFavorite = [NSNumber numberWithBool:isFavorite];

    // If the post is being favorited and not yet in the local database, add it
    NSError *error;
    if (isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] == nil) {
        [self.managedObjectContext insertObject:post];
    }
    // Else if the post is being un-favorited and is in the local database, delete it
    else if (!isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] != nil) {
        [self.managedObjectContext deleteObject:post];
    }

    // If there was an error, output and return NO to indicate a failure
    if (error) {
        NSLog(@"error: %@", error);
        return NO;
    }

    return YES;
}

お役に立てば幸いです。

于 2012-07-12T13:55:48.887 に答える
1

存在するコンテキストを保存していることを確認する必要がありますmanagedObject。同じオブジェクトを別のコンテキストでフェッチするには、永続ストアに存在する必要があります。

ドキュメントによると、はobjectWithID:常にオブジェクトを返します。したがって、障害がオブジェクトに解決されるという事実は、すべてのnil値が永続ストアでオブジェクトを検出していないことを意味します。

于 2010-06-08T15:27:30.407 に答える
1

スウィフト5

2020年にNSManagedObjectsをコピーする方法がわからない場合は、以下のコードが有効です。

// `Restaurant` is the name of my managed object subclass.

// I like to have Xcode auto generate my subclasses (Codegen 
//     set to "Class Definition") & then just extend them with 
//     whatever functionality I need.

extension Restaurant {
    public func copy() -> Restaurant? {
        let attributes = entity.attributesByName.map { $0.key }
        let dictionary = dictionaryWithValues(forKeys: attributes)
        guard let context = AppDelegate.shared?.persistentContainer.viewContext,
            let restaurantCopy = NSEntityDescription.insertNewObject(forEntityName: Restaurant.entityName, into: context) as? Restaurant
            else
        {
            return nil
        }
        restaurantCopy.setValuesForKeys(dictionary)

        return restaurantCopy
    }
}
于 2020-01-30T23:39:55.160 に答える