WWDC Quick Look 💓 By SwiftGGTeam
Evolve your Core Data schema

Evolve your Core Data schema

元の動画を見る

ハイライト

Core Data can infer many schema migrations from source and destination models automatically, while CloudKit-backed stores still require additive schema design, Development initialization, and Production promotion.


主要内容

Core Data のデータ モデルが変更されると、ディスク上のストレージ構造も変更する必要があります。

(01:00) セッションはAircraftエンティティ記述の問題: モデル内にありますtypeそしてnumberOfEngines、SQLite ストレージにも対応する列があります。追加するときnumberOfPassengers、基礎となるストレージも対応する構造を追加する必要があります。

移行がなければ、Core Data は古いストアを開くことを拒否します。エラーコードはNSPersistentStoreIncompatibleVersionHashError(01:36)。このエラーは、現在のモデルがストア作成時のモデルと一致しないことを示します。

Apple は、最初に軽量移行を使用することをお勧めします。ソース管理オブジェクト モデルと宛先管理オブジェクト モデルを比較し、マッピング モデルを自動的に生成し、モデルの変更をデータベース スキーマに追加します (01:59)。

このスピーチの焦点は次の 3 つです。

  1. どのコア データ モデルの変更を軽量移行に引き渡すことができますか。
  2. 複雑な変更を複数の軽量移行に分割する方法。
  3. Core Data が CloudKit と同期されている場合のスキーマ移行の制限は何ですか。

詳細

1. 軽量移行ではどのような変更に対応できますか?

(02:54) 軽量移行の対象となる属性変更には、新しい属性の追加、属性の削除、非オプション属性のオプションへの変更、オプション属性の非オプションへの変更とデフォルト値の指定、および属性の名前変更が含まれます。

名前を変更するには、名前変更識別子を設定します。たとえば、次のように置きますAircraft.colorに変更しますAircraft.paintColor、宛先モデル内paintColor名前変更識別子をソースモデル内の識別子に設定する必要がありますcolor(03:11)。 Core Data はこの識別子を使用して安定した正規名を確立し、バージョン 1 からバージョン 3 までのクロスバージョン パスをサポートします。

関係とエンティティも移行できます。関係は追加、削除、名前変更でき、またカーディナリティは対 1 / 対多、順序付き / 順序なし (04:00) の間で変更できます。エンティティは追加、削除、名前変更でき、属性は継承階層内で上下に移動したり、エンティティを階層内外に移動したりできます (04:29)。

覚えておくべき制限が 1 つあります。共通の親エンティティを持たない 2 つのソース モデル内の既存のエンティティは、宛先モデルの同じ親エンティティの下にマージできません (04:53)。

軽量移行の 2 つの主要なオプションは次のとおりです。

NSMigratePersistentStoresAutomaticallyOption
NSInferMappingModelAutomaticallyOption

キーポイント:

  • NSMigratePersistentStoresAutomaticallyOption: ストアと現在のモデルの間に不一致が見つかった場合に、Core Data が移行を実行できるようにします。 -NSInferMappingModelAutomaticallyOption: Core Data がモデルの違いに基づいてマッピング モデルを推測できるようにします。
  • 使用されている場合NSPersistentContainerまたはNSPersistentStoreDescription、これら 2 つのオプションは自動的に設定されます (05:31)。
  • 直接使用する場合NSPersistentStoreCoordinator.addPersistentStore(...)、オプション ディクショナリを手動で渡す必要があります。

2. ストアを手動で開くときに軽量移行を有効にする方法

(06:16) Session によって与えられたコードは、3 番目のアプローチを示しています。NSPersistentStoreCoordinatorただし、永続ストアを追加するときに移行オプションを渡します。

import CoreData

let storeURL = NSURL.fileURL(withPath: "/path/to/store")
let momURL = NSURL.fileURL(withPath: "/path/to/model")
guard let mom = NSManagedObjectModel(contentsOf: momURL) else {
    fatalError("Error initializing managed object model for URL: \(momURL)")
}
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: mom)
do {
    let opts = [NSMigratePersistentStoresAutomaticallyOption: true,
                NSInferMappingModelAutomaticallyOption: true]

    try coordinator.addPersistentStore(ofType: NSSQLiteStoreType,
                                       configurationName: Optional<String>.none,
                                       at: storeURL,
                                       options: opts)
} catch {
    fatalError("Error configuring persistent store: \(error)")
}

キーポイント:

  • import CoreData: Core Data の管理対象オブジェクト モデル、コーディネーター、ストア オプションを使用します。 -storeURL: 既存の永続ストアのパスを指します。 -momURL: 現在のアプリケーションで使用される管理対象オブジェクト モデルを指します。 -NSManagedObjectModel(contentsOf:): モデル ファイルから宛先モデルをロードします。後続の移行にはモデルの基礎がないため、読み込みが失敗した場合は直接停止します。 -NSPersistentStoreCoordinator(managedObjectModel:):現在のモデルを使用してコーディネーターを作成します。 -NSMigratePersistentStoresAutomaticallyOption: true: 自動移行をオンにします。 -NSInferMappingModelAutomaticallyOption: true: Core Data がマッピング モデルを推測できるようにします。 -addPersistentStore(...): 実際にストアを開きます。ストアのモデルのバージョンが一致しない場合、ここで移行が発生します。 -catch: ストアを開いたとき、または移行が失敗したときにエラーをキャプチャします。

Core Data がマッピング モデルを推論できるかどうかを事前に確認したい場合は、次のように呼び出します。NSMappingModel.inferredMappingModel(06:56)。推論できる場合はマッピング モデルを返し、推論できない場合はマッピング モデルを返します。nil

3. 複雑な変更を複数の軽量移行に分割する

(07:19) 一部の変更の組み合わせは、軽量の移行機能を超えています。スピーチ用flightData例: 当初はバイナリ データ用に外部ストレージを使用していましたが、後で内部ストレージに変更し、外部ファイル パスを削除したいと考えました。モデル A からモデル B への直接移行は、軽量移行ルールに準拠しません。

このアプローチは、ブリッジ モデルを導入し、複雑な移行を Core Data が理解できる複数のステップに分割することです (08:16)。

Session の逆アセンブリ方法は次のとおりです。

  1. モデル A から A’ を作成し、一時属性を追加しますtmpStorage
  2. 移行の間にアプリケーション独自のインポート ロジックを実行して、外部ファイル データを書き込みますtmpStorage
  3. A’ から A” を作成し、古い外部ストレージ プロパティを削除して、新しいプロパティの名前を最終的な名前に変更します。

各ステップは軽量の移行機能の範囲内にあります。 Core Data はスキーマの移行を担当し、外部ファイルのインポートのビジネス ロジックはアプリケーション自体によって実行されます (09:26)。

キーポイント:

  • ブリッジ モデルの目標は、移行不可能な変更をユーザーによる長期使用のために保持するのではなく、より小さな部分に分割することです。
  • アプリケーション固有のインポート ロジックは、2 つの軽量移行の間に配置する必要があります。
  • 移行プロセスがシステムによって終了される可能性がある場合は、インポート ロジックが再起動可能である必要があります (10:19)。
  • 未処理のモデルを順番に開くループを構築し、Core Data にストアを段階的に移行させることができます (10:04)。

4. CloudKit 同期中の移行の制限事項

(10:34) Core Data が CloudKit と同期する場合、両者はデータ モデルについての理解を共有する必要があります。 Core Data モデル エディターで定義されたモデルは、CloudKit スキーマの生成に使用されます。スキーマは最初に開発環境に生成され、次に実稼働環境にプロモートされます。

CloudKit は、Core Data モデルのすべての機能をサポートしているわけではありません (11:07)。セッションには、いくつかの種類の制限が明確にリストされています。

  • エンティティの一意の制約はサポートされていません。 -UndefinedそしてobjectID属性タイプはサポートされていません。
  • 関係はオプションである必要があり、逆の関係が存在する必要があります。
  • 削除拒否ルールはサポートされていません。

実稼働スキーマにはさらに厳しい制約もあります。 CloudKit スキーマが運用環境に昇格されると、レコード タイプとフィールドは不変になります (11:43)。 CloudKit は新しいフィールドと新しいレコード タイプをサポートします。既存のレコード タイプまたはフィールドは変更または削除できません (12:07)。

これは、コア データの移行の境界に影響します。軽い移行ではローカル ストア ファイルのみが変更され、CloudKit スキーマは自動的に変更されません (12:26)。モデルが CloudKit で使用されている場合は、スキーマ初期化子を実行し、変更を開発データベースに書き込み、CloudKit コンソールを使用して実稼働環境にアップグレードする必要もあります。

セッションでは、3 つの CloudKit スキーマ進化戦略 (13:33) を示します。

  1. 既存のレコード タイプに新しいフィールドを段階的に追加します。
  2. エンティティに version 属性を追加し、フェッチ リクエストを使用して現在のアプリ バージョンと互換性のあるレコードのみをフェッチします。
  3. 使用するNSPersistentCloudKitContainerOptions新しいストアを新しいコンテナに関連付けます。

キーポイント:

  • 最初の戦略では、古いバージョンのアプリでもユーザーが作成したレコードにアクセスできますが、すべてのフィールドは表示されません。
  • 2 番目の戦略では、古いバージョンのアプリで、新しいバージョンによって作成された互換性のないレコードを非表示にすることができます。
  • 3 番目の戦略では、データ セットを再アップロードします。ユーザーデータが大きい場合、アップロードに時間がかかることがあります。
  • どの戦略でも、異なるアプリ バージョンと異なるデータ モデル バージョンの共存をテストする必要があります (14:33)。

5. 移行プロセスのデバッグ

(15:21) デモ セクションでは、2 つの環境変数が開きます。com.apple.CoreData.SQLDebugそしてcom.apple.CoreData.MigrationDebug。 Core Data は、ファイルの作成、ストア メタデータの書き込み、スキーマの具体化、移行の実行などの手順を出力します。

まだ利用可能sqlite3SQLite ストアを検査するためのコマンド ライン ツール。まずはデモで確認ZLOGENTRYテーブルには元のモデルに対応する列が含まれており、モデルを変更して移行を有効にし、アプリケーションを再実行して、最後に新しいスキーマが Core Data によって自動的にダウンロードされたことを確認します (15:52)。

キーポイント:

  • NSPersistentStoreIncompatibleVersionHashError移行エントリー信号です。 -SQLDebug基礎となるスキーマが期待どおりに作成または更新されているかどうかを確認するのに役立ちます。 -MigrationDebugCore Data が実際に移行を実行するかどうかを観察するのに役立ちます。 -sqlite3ストア ファイル内のテーブルと列は個別に検証できます。

重要ポイント

1. モデル移行事前チェックツールを作成する

  • 対処方法: 開発ビルドで、現在のモデルと過去のモデルに対して移行機能チェックを実行します。
  • 実行する価値がある理由:NSMappingModel.inferredMappingModel実際の移行前に、Core Data がマッピング モデルを推論できるかどうかを判断できます。
  • 開始方法: アプリ バンドル内の履歴管理オブジェクト モデルを収集し、それらをペアごとに呼び出しますNSMappingModel.inferredMappingModel、失敗したときに CI またはローカル デバッグ パネルで特定のバージョンをマークします。

2. CloudKit ベースのモデルに互換性チェックを追加します

  • 対処方法: モデル レビュー スクリプトで CloudKit によってサポートされていないコア データ デザインがないか確認します。
  • 実行する価値がある理由: CloudKit は一意の制約をサポートしていません。UndefinedobjectID、逆関係の欠如、削除ルールの拒否。
  • 開始方法: トラバーサルNSManagedObjectModelエンティティ、属性、関係、削除ルール、および非互換性をビルド警告として出力します。

3. 再開可能なデータインポート移行の設計

  • やるべきこと: 外部ファイルのインポートや反復可能なタスクへのフィールドの入力などの移行手順を実行します。
  • 実行する価値がある理由: セッションでは、プロセス終了後に特定の移行ロジックのアプリケーションを再起動できることが明示的に必要です。
  • 開始方法: 処理される各オブジェクトの移行ステータスを記録し、インポートが成功した後に完了としてマークします。次回の起動時には、未完了のオブジェクトのみが処理されます。

4. マルチバージョンアプリ用の CloudKit 回帰データセットを作成する

  • 対処方法: アプリの古いバージョンと新しいバージョンの両方で同じ CloudKit 開発コンテナにアクセスし、レコード タイプ、フィールド、およびバージョン属性ポリシーを確認します。
  • 実行する価値がある理由: ユーザーのデバイスはアプリの古いバージョンと新しいバージョンの両方を同時に実行し、運用スキーマは追加的です。
  • 開始方法: まず開発環境でフィールドまたはレコード タイプを追加し、古いバージョンのアプリを実行してレコードの作成と読み取りを行い、次に新しいバージョンのアプリを実行して新しいフィールドを書き込み、表示を確認して古いバージョンの結果を取得します。

関連セッション

コメント

GitHub Issues · utterances