6

次の単純なエンティティ モデルを考えてみましょう。エンティティ A には、bというエンティティ B との 1 対 1 の関係があります。エンティティ B には、 aと呼ばれる逆対一の関係があります。どちらの関係もオプションではありません。

A            B
b  < ----- > a

完全に同期を開始する 2 つのデバイス (1) と (2) があるとします。それぞれに、クラス A のオブジェクトが 1 つと、クラス B のオブジェクトが 1 つあり、それらは互いに関連付けられています。デバイス 1 にはオブジェクト A1 と B1 があり、デバイス B には同じ論理オブジェクト A1 と B1 があります。

次に、各デバイスでシミュレートされた変更が行われたとします。

デバイス 1 で、B1 を削除し、B2 を挿入して、A1 を B2 に関連付けます。次に、変更を保存します。
デバイス 2 では、B1 を削除し、B3 を挿入して、A1 を B3 に関連付けます。次に、変更を保存します。

デバイス 1 は、デバイス 2 からトランザクション ログをインポートしようとします。B3 が挿入され、A1 が B3 に関連付けられます。ここまでは順調ですが、B2 にはnilに等しい関係aが残されています。関係はオプションはないため、検証エラーが発生します。

B オブジェクトが 2 つあり、関連付けられる A オブジェクトが 1 つだけであるため、デバイス 2 でも同様のことが起こります。したがって、B オブジェクトの 1 つがnilに設定され関係を持つ必要があるため、常に検証エラーが発生する必要があります。

さらに悪いことに、将来の変更では、常に誤った B オブジェクトがぶら下がったままになり、検証に失敗します。実際には、ユーザーは関係をリセットしても問題を自分で解決することはできません。永久に壊れています。

問題は、このような検証エラーにどのように対処できるかということです。これはすべて、NSPersistentStoreDidImportUbiquitousContentChangesNotification通知がトリガーされる前に発生します。アプリの mainNSManagedObjectContextでの検証エラーではなく、トランザクション ログを永続ストアに最初にインポートするときに発生する検証エラーです。

私が考えることができる唯一のオプションは、おそらくカスタムセッター ( setA:) または B クラス自体の KVC 検証メソッド ( validateA:error:) で無効な B オブジェクトを削除しようとすることです。これらはトランザクションログのインポート中にトリガーされるように見えるためです。 . しかし、これらのような副作用が許されているかどうかはわかりません。試してみると、その影響に関する厄介なログ メッセージが表示されるようです。

これを処理する正しい方法を知っている人はいますか?

4

2 に答える 2

2

Appleの開発者フォーラムでこのスレッドをチェックしてください:

https://devforums.apple.com/message/641930#641930

Appleの従業員からの返答があります。一言で言えば:

1)これは、iOS(5.1)およびOS X(10.7.3)の現在のバージョンでのCoreDataiCloud同期の既知のバグです。

2)関係が検証述語でオプションではない場合、同期は完全に停止します。したがって、物事の流れを維持するために、当面は検証を削除する必要があります。ただし、そうすると、デバイスのデータが一致しなくなります。

3)これに対する公式の回避策はありません。面倒なアプローチの1つは、関係を追跡する別の属性を維持することです。次に、iCloudを介して変更されたオブジェクトをスキャンし、関係がゼロの場合は修正する必要があります。

私もこのバグに噛まれています。トラブルに見舞われたお客様に対応するのは非常に苛立たしいことです。うまくいけば、Appleからの修正がすぐに出ます...

于 2012-04-17T23:51:38.467 に答える
1

これが他の人に役立つ場合に備えて、iCloud のこのバグを回避する作業をもう少し進めました。私が行ったことは、最初のトランザクション ログのインポート中に検証を無効にし、MOC をメイン ストアに保存するときに再度有効にしました。もちろん、検証エラーは引き続き発生しますが、Core Data フレームワークの奥深くではなく、MOC 保存メソッドで発生するため、エラーを修復できます (無効なオブジェクトの削除など)。

検証を「無効」にするにはどうすればよいですか? 私が行っている方法は、すべての Core Data エンティティ クラスのルート クラスとして使用した NSManagedObject サブクラスの KVC 検証メソッドをオーバーライドすることです。

-(BOOL)validateValue:(__autoreleasing id *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error 
{
    if ( ![self.managedObjectContext isKindOfClass:[MCManagedObjectContext class]] ) {
        return YES;
    }
    else {
        return [super validateValue:value forKey:key error:error];
    }
}

オーバーライドでは、マネージド オブジェクト コンテキストのクラスをチェックし、それが自分のカスタム クラスである場合は、スーパー メソッドにチェーンすることで通常どおり検証を行います。それが私のカスタム サブクラスでない場合は、有効性を示すために YES を返します。

もちろん、これをもっと微妙にすることもできますが、うまくいけばアイデアが得られます: これがアプリの標準保存の 1 つなのか、iCloud インポート保存なのかを判断し、それに応じて分岐します。

于 2012-04-18T10:25:38.177 に答える