19

私の質問を効果的にするために、まず私が直面している正確なシナリオを考えてみましょう:

一般的な設定

  • ホスト iOS 8 アプリ。
  • ホスト アプリにバンドルされている 1 つ以上の iOS 8 拡張機能 (WatchKit、Share など)。
  • ホスト アプリとすべての拡張機能は、共有アプリ グループ コンテナー内の同じ Core Data SQLite ストアを共有します。
  • 各アプリ/拡張機能には、独自の NSPersistentStoreCoordinator と NSManagedObjectContext があります。
  • 各永続ストア コーディネーターは、他のすべての永続ストアと同じ SQLite リソースをグループ コンテナー内で共有する永続ストアを使用します。
  • アプリとすべての拡張機能は、共通のコードベースを使用して、インターネット上のリモート API リソースからコンテンツを同期します。

問題につながる一連のイベント

  1. ユーザーがホスト アプリを起動します。リモート API リソースからのデータのフェッチを開始します。コア データ モデル オブジェクトは、API 応答に基づいて作成され、ホスト アプリのマネージド オブジェクト コンテキストに「アップサート」されます。各 API エンティティには、リモート API バックエンドでそれを識別する uniqueID があります。「アップサート」とは、API エンティティごとに、特定の uniqueID の既存のエントリが見つからない場合にのみ、ホスト アプリが Core Data に新しいエントリを作成することを意味します。

  2. 一方、ユーザーはホスト アプリの拡張機能の 1 つも起動します。これも、同じリモート API から何らかのフェッチを実行します。また、API 応答を解析するときに「アップサート」を実行しようとします。

  3. 問題:ホスト アプリと拡張機能の両方が同じ API エンティティのコア データ エントリを同時にアップサートしようとするとどうなりますか? これがどのように発生するかを確認するために、アップサートの一連のイベントを見てみましょう。

コア データ アップサート シーケンス:

  1. API 解析コードは、特定の API エンティティの uniqueID を解析します。
  2. uniqueIDパーサーは、解析された uniqueID と等しい述語に一致するすべてのエントリに対してコア データ フェッチを実行します。
  3. 既存のエントリが見つからない場合、パーサーはこの API エンティティの新しい Core Data エントリを挿入し、そのuniqueID属性を解析済みの uniqueID に設定します。
  4. パーサーは管理オブジェクト コンテキストを保存し、新しいエントリ データを SQLite バッキング ストアにプッシュします。

問題の詳細

ホスト アプリと拡張機能が、同じ API エンティティの API 応答を同時に個別に解析しているとします。ホスト アプリと拡張機能の両方がステップ 4 を完了する前にステップ 3 に到達した場合、両方とも同じ uniqueID の新しい Core Data エントリを挿入しようとします。ステップ 4 に到達save:し、それぞれの管理対象オブジェクト コンテキストを呼び出すと、Core Data は問題なく重複したエントリを作成します。

私の知る限り、Core Data には属性を一意としてマークする方法がありません。SQLite INSERT OR IGNORE+UPDATEコンボに相当する Core Data が必要です。. または、永続ストアの SQLite バッキング ストアを「ロック」する方法が必要です。これは、トラブルのレシピのように聞こえます。

iOS 8 拡張機能によって導入された、このかなり新しい問題に対する既知のアプローチはありますか?

4

2 に答える 2

10

It seems like the simplest approach to this would be to simply avoid the multiple writers in the first place. Why not just drive your extensions entirely off cached data, and then only update your data store from your primary iOS app?

于 2014-11-19T17:08:29.243 に答える