1

Appleのドキュメントでは見つけられないシンプルで一般的なパターン:

  1. CoreDataストアをロードする
  2. 新しいデータをダウンロードし、メモリ内にオブジェクトを作成します
  3. 新しいデータの一部をストアに保存します(通常は「変更されていない新しいビット/ビットのみ」)

代わりに、私はこれらの選択肢を見つけることができますが、どれも正しくありません:

  1. メモリ内にオブジェクトを作成しないでください(これは、オブジェクトの優れた点をすべて破棄することを意味します。CoreDataの障害を回避する以外の目的を果たさない多くのNSDictionaryを使用してコードを記述します。一般的には機能しません)
  2. オブジェクトを作成しますが、不要なオブジェクトは削除します(Appleはドキュメントでこれを提案していますが、通知はひどく間違っています。保存しようとすると、保存しようとすると表示されますが、保存できない/できません)
  3. セカンダリコンテキストでオブジェクトを作成する(Appleはこれが正しいことを強く示唆していますが、上記を実行せずに、オブジェクトを一時コンテキストから実際のコンテキストに移動する方法を提供していないようです(作成したオブジェクトを削除してから、オブジェクトは多くの場合、新しいコンテキストの参照に接続する必要があり、保存は失敗するため、これは一般的には不可能です)

確かに、これほど難しいことではないでしょうか?

オブジェクトを手動でディープコピーするためにすべてのコードを作成する必要がある場合(すべてのフィールドとデータ構造を反復処理することにより)、そもそもCoreDataが存在するのはなぜですか?これは、CDが内部で提供する基本的な機能です。

私がこれまで取り組んできた唯一の解決策は、オプション2(Appleのドキュメントから)であり、Appleが最初に保存されるべきではなかったオブジェクトのNSNotificationsを送信するときに「推測」するカスタムヒューリスティックを使用します(ただし、Appleはとにかくnotoficationsを送信します)。それは恐ろしいハックです。

編集:説明:

Appleの通知を正しく配信する方法がわかりません。Appleのコードは、挿入を「更新」に変換し、「一時的なオブジェクト」を「削除」に変換するようです。「新しいオブジェクト」を聞くことができません。

4

3 に答える 3

2

これを処理するには、3 つの一般的な方法があります。

  1. 「実際の」コンテキストと同じ永続ストアを持つ一時オブジェクト コンテキストを作成し、この一時コンテキストにオブジェクトを追加します。保持するオブジェクトがわかったら、一時コンテキストから他のすべてのオブジェクトを削除し、一時コンテキストを保存します。保存すると、NSManagedObjectContextDidSaveNotification 通知を観察して「実際の」コンテキストを更新し、それを「実際の」コンテキストにマージできます (ala [realContext mergeChangesFromContextDidSaveNotification:notification])。詳細については、Mike Weller の回答を参照してください

    (I/O が気になる場合は、長所と短所があるインメモリ コンテキストを使用できます。)

  2. NSManagedObject を使用する代わりに、NSDictionary を使用します。保持するオブジェクトがわかったら、新しい管理対象オブジェクトをインスタンス化し、[managedObject setValuesForKeysWithDictionary:temporaryObject] を呼び出して一時オブジェクトから管理対象オブジェクトに値をコピーし、「実際の」コンテキストを保存します。NSManagedObjects と一時オブジェクト (テーブル ビューなど) を操作する必要があるコードがある場合は、キー値コーディング (別名 valueForKey:、setValue:forKeyPath:) を使用してそのコードを記述します。

  3. エンティティ モデルに「isTemporary」属性を追加します (デフォルトは NO)。一時オブジェクトを作成するときは、isTemporary を YES に設定し、オブジェクトを「実際の」コンテキストに挿入します。保持するオブジェクトがわかったら、それらの isTemporary 属性を NO に変更します。もちろん、これらの一時オブジェクトを定期的に削除する必要がありますが、それは簡単です (たとえば、そのタスクが完了したとき、アプリの終了時など)。

#1 と #3 の利点は、オブジェクトが CoreData の世界に存在することです。たとえば、クエリを実行したり、リレーションシップに参加したりできます。#2 の利点は、軽量で高速であることです。多くの一時オブジェクト。

于 2011-04-03T04:08:23.550 に答える
1

オプション 3 が最良の選択肢のようです。

編集: iOS 4 でこれを広範囲に使用した後、「常に performSelectorOnBackgroundThread の代わりに NSOperationQueue を使用する」と言うでしょう。NSOpQ を簡単に使用する方法がわからない場合は、Google で検索してください。ただし、3 行未満のコードで実行できるため、performSel を使用することからの小さな変更にすぎません。これは、 iOS4の新しいスレッド スケジューラとの相性が抜群です。

「これを機能させるにはどうすればよいですか?」に基づいて、次のアプローチを思い付きました。

  1. 元のクラスには、独自のコンテキストが必要です。プライベート コンテキストで (NSNotification を介して) 「変更」をリッスンするためにサブスクライブする必要があります。
  2. 「performSelectorOnBackgroundThread」などを使用してダウンロード メソッドのみを呼び出します (強制的に別のスレッドに移動させます)。
  3. NSManagedObjects ではない上記のメソッド呼び出しに常に引数を渡し、それらを参照しないでください (これは performSelector を使用することによって強制されます... とにかく - しかし、同じスレッドにいる場合でも、後で Apple のコードを台無しにします。他の方法で行う)
  4. 新しいものが接続する必要がある「既存の」managedObjects の ID を常に提供する
  5. ダウンロードを開始する前に、常に新しい一時的な NSManagedContext を作成してください。
  6. ...この「一時的な」コンテキストの「保存」をリッスンするために(NSNotificationsを使用して)実行していた元のクラスを常に登録します
  7. ダウンロードを行い、オブジェクトを作成し、不要なものを削除します
  8. 次に、ID で渡したオブジェクトを (一時的なコンテキストで) 常に再フェッチし、それらを新しく作成されたオブジェクトにフックします。
  9. 一時的なコンテキストを保存します
  10. ORIGINAL クラスは、メイン スレッド上でコールバックを再呼び出しすることによって「保存されたコンテキスト」に反応します (まだメイン スレッド上にない場合 - [NSThread isMainThread])。
  11. ORIGINAL クラスは、メイン スレッドで実行されるとすぐに、Apple の「マージ」メソッドを使用して、NSNotificaiton オブジェクトを独自のストアにマージします。
  12. ORIGINAL クラスは、変更を処理することによって「変更されたコンテキスト オブジェクト」に反応します。

ただし...これには、Appleのドキュメントに記載されていないことも必要です。残りのすべてへの参照を持つ「ルート」オブジェクトを除いて、管理対象オブジェクトへの参照を保存しないでください。

そうしないと、Apple の「マージ」がうまく機能しなくなります。

また...これを機能させるには、フォールトを手動で「刺激」する必要がある場合があります。それについていくつかの質問があります(Appleがこれを自動的に行わない理由はわかりません-おそらくそうですが、そうである場合、これを実現するための魔法のオプションはまだ見つかりません)。

他にも注意点はあると思います。覚えていたら後で編集します。

注意: これは非常に多くのコードのように思えます。はい、しかし...辞書などによるオブジェクトの手動コピーを使用して曲がりくねった例に従おうとするよりもはるかに少ないことがわかります。

このセットアップと作業が完了すると、概念的には非常に簡単に従うことができます。また...上記のすべての手順を実行すると、AppleはNSNotificationsの「ほとんど」を正しく取得します。正しくないように見える残りのもの (たとえば、いくつかの削除) は、「ドキュメントに記載されているとおり」です。それらは私には意味がありませんが、少なくともそれが機能するように文書化されています.

于 2010-07-05T12:04:12.967 に答える
0

オブジェクトには、一意の整数 ID などの一意の識別子が必要です。これは Core Data の外部から取得され、ビジネス ロジックに依存します。そのため、外部から新しいオブジェクトを受け取ると、この ID を持つオブジェクトが Core Data に既に存在するかどうかを確認します。存在する場合は、既存のオブジェクトを編集します。いいえの場合は、新しいオブジェクトを追加します。

于 2010-07-04T02:50:56.517 に答える