2

概要

私の問題は、 Ensemblesを使用して iCloud と同期するCore Data ベースの iOS プロジェクトでほぼ重複するものを取り除きたいということです。

  • 私のアプリでは、iCloud との同期は基本的にうまく機能します。
  • 問題は、永続ストアが (iCloud に接続された) Ensembles によってリーチされる前に、ユーザーが複数のデバイスで同様のオブジェクトを作成する場合です。
  • これにより、事実上正しいほぼ重複が生成されます。
  • これらの重複を削除する私のアプローチはうまくいかないようです。

詳細な問題

ユーザーはNSManagedObjects、iCloud に接続する前に、さまざまなデバイスで作成できます。彼が と"対多" の関係を持つ名前付きに対して "対 1" の関係を持つNSManagedObject名前を持っているとしましょう。これは次のようになります。 CarNSManagedObjectPersonCar単純化されたモデル

ユーザーが 2 つのデバイスを持っていてNSManagedObjects、各デバイスに 2 つ作成するとします。Car「アウディ」という名前Personと「ラファエル」という名前。両方が関係を通じて接続されました。もう一方のデバイスで、彼はCar「BMW」という名前のデバイスPersonと「Raphael」という名前の別のデバイスを作成します。また、相互に接続されています。これで、ユーザーは各デバイスに 2 つの類似したオブジェクトを持ちます:Person両方とも「Raphael」という名前の 2 つのオブジェクト。

私の問題は、ユーザーがPerson同期した後、各デバイスに「Raphael」という名前のオブジェクトが 2 つあることです。

ユーザーが永続ストアをリーチすると、オブジェクトは (アンサンブル内のオブジェクトを識別するために) uniqueIdentifiers を取得するため、これは実際には正しいです。オブジェクトは実際には異なります。しかし、これは私が修正したいものです。

私のアプローチ

このデリゲート メソッドを実装し、reparationContext の重複を削除しました。

- (BOOL)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble 
    shouldSaveMergedChangesInManagedObjectContext:(NSManagedObjectContext*)savingContext
    reparationManagedObjectContext(NSManagedObjectContext *)reparationContext {

    [reparationContext performBlockAndWait:^{

        // Find duplicates
        // Change relationships and only use the inserted Person object (the one from iCloud)
        // Delete local Person object
        [reparationContext save:nil];
    }
    return YES;
}

基本的に、これは最初のデバイスからのデータをマージする 2 番目のデバイスでうまく機能するようです。残念ながら、reparationContext で削除された場合でも、ローカルの人はまだ iCloud に同期されているようです。

これは、最初のデバイスが 2 番目のデバイスからの変更をマージし、2 番目のデバイスで既に削除された人を再び置き換えるため、壊れた状態につながります。後でいくつかの同期を行うと、車の関係でその人が最終的に行方不明になり、アプリは同期エラーをスローします。

問題を再現する手順

  • ステップ 1 (デバイス 1)

    • オブジェクトを作成する
    • データ: 車「アウディ」 -> 人「ラファエル (デバイス 1)」
  • ステップ 2 (デバイス 2)

    • オブジェクトを作成する
    • データ: 車「BMW」 -> 人物「ラファエル (デバイス 2)」
  • ステップ 3 (デバイス 1)

    • ストアからのリーチ データ
    • iCloudに接続
    • iCloudにデータを送る
    • データ: 車「アウディ」 -> 人「ラファエル (デバイス 1)」
  • ステップ 4 (デバイス 2)

    • ストアからのリーチ データ
    • iCloudに接続
    • iCloud からのデータをマージする
    • デバイス 2 のローカルの人をデバイス 1 の挿入された人に置き換えます
    • デバイス 2 からローカルの人を削除する
    • iCloudにデータを送る
    • データ:
      車 "Audi" -> 人物 "Raphael (Device 1)"
      車 "BMW" -> 人物 "Raphael (Device 1)"
  • ステップ 5 (デバイス 1)

    • iCloud からのデータをマージする
    • デバイス 1 のローカルの人をデバイス 2 の挿入された人に置き換えます (これは発生しないはずです)。
    • デバイス 1 からローカルの人を削除します (これは発生しないはずです)。
    • iCloudにデータを送る
    • 期待されるデータ:
      車 "Audi" -> 人 "Raphael (Device 1)"
      車 "BMW" -> 人 "Raphael (Device 1)"
    • 実際のデータ:
      車 "Audi" -> 人物 "Raphael (Device 2)"
      車 "BMW" -> 人物 "Raphael (Device 2)"

実際にはステップ 4 でローカル人物オブジェクト「Raphael (Device 2)」が削除されましたが、ステップ 5 でデリゲート メソッド savingContext.insertedObjectsから挿入としてポップアップされるため、iCloud に送信されたままになっているようです。shouldSaveMergedChangesInManagedObjectContext

私が理解している限り、Ensembles は最初に iCloud から変更を取得し、デリゲート メソッドを介してすべてが期待どおりかどうかをユーザーに尋ね、次に永続ストアにマージし、マージ後にデルタを iCloud に送信します。

私は何か間違ったことをしていますか?それとも、これは Ensembles のバグですか?

4

2 に答える 2

2

ラーズが言及した問題があります。常に決定論的に物事を行うように注意する必要があります。一意の ID でソートすることは、そのための 1 つの方法です。

個人的には、次の 2 つの方法のいずれかを処理します。

  1. マージが完了した後に重複除外を実行します (これも決定論的であることを確認します)。
  2. 慎重に選択されたグローバル識別子を使用して重複除外を制御します。

たとえば、一意の id を使用できますRaphael。次に注意する必要がある唯一のことは、同じマシンで別の Raphael を作成しようとすると、それが呼び出されることですRaphael_1(または何でも)。

一意の ID が一意である可能性が非常に高い場合 (たとえば、名と姓が衝突する可能性が低い場合)、Ensembles は異なるデバイス上の人物を自動的にマージします。

于 2016-01-25T12:29:32.000 に答える