WWDC Quick Look 💓 By SwiftGGTeam
Dive deeper into SwiftData

Dive deeper into SwiftData

元の動画を見る

ハイライト

SwiftData の中核は Model の 2 つの役割です。これは、オブジェクト グラフを記述するスキーマと、コード内で直接操作するためのインターフェイスの両方です。 ModelContainer は永続的な構成を担当し、ModelContext はメモリ内のオブジェクトのステータスの追跡と管理を担当します。この 2 つが連携して、データ操作が直感的かつ安全になります。

主要内容

コードから永続化まで: 距離を最小限に抑える

以前は、データの永続化には、モデル クラスの作成、データベース オペレーション コードの作成、スレッド同期の処理、オブジェクトのライフ サイクルの管理が必要でした。 Core Data は強力ですが、学習曲線が急峻で、定型的なコードが大量にあります。

SwiftData の設計目標は、「通常の Swift コード」と「永続性のある Swift コード」の間の距離を最小限に抑えることです。

(01:44) SampleTrips アプリケーションの Trip クラス、および@Modelマクロといくつかのリレーショナル アノテーションにより、完全な永続化機能が提供されます。 SwiftData はオブジェクト グラフ構造を自動的に推測するため、追加の構成は必要ありません。

コア アーキテクチャは、次の 2 つの主要なコンポーネントで構成されます。

  • ModelContainer: スキーマと永続性の間のブリッジ、ストレージの場所、バージョン管理、移行、オブジェクト グラフの分離などを処理します。
  • ModelContext: データのメモリ内ビュー。オブジェクトはコンテキストにフェッチされ、編集内容は呼び出されるまでスナップショットとして記録されます。save()耐久性がある

SwiftData は SwiftUI ネイティブ統合を提供します (modelContainer修飾子)、タイプセーフなクエリ (FetchDescriptor + #Predicateマクロ)、システムレベルの取り消し/自動保存のサポート、効率的なバッチ トラバーサル (enumerate)およびその他の能力。

詳細

ModelContainer: スキーマと永続性の間の架け橋

(03:54) ModelContainer は、デバイス上のデータが保存される場所です。これはスキーマと永続性の間のブリッジであり、ストレージの場所、バージョン管理、移行、オブジェクト グラフの分離などを処理します。

最も単純な初期化方法:

let container = ModelContainer(for: Trip.self)

重要なポイント:

  • 型を渡すと、SwiftData が完全なスキーマ (関連する型を含む) を自動的に推論します。 -Trip関連するBucketListItemそしてLivingAccommodation、これらのタイプには自動的に含まれます

ModelConfiguration: 永続性の細かい制御

(04:53) 複雑なシーンの場合ModelConfiguration永続性の詳細を説明します。

let schema = Schema([Trip.self, BucketListItem.self, LivingAccommodation.self, Person.self, Address.self])

let tripsConfig = ModelConfiguration(
    schema: schema,
    isStoredInMemoryOnly: false,
    cloudKitDatabase: .automatic("com.example.SampleTrips")
)

let peopleConfig = ModelConfiguration(
    schema: schema,
    isStoredInMemoryOnly: false,
    cloudKitDatabase: .automatic("com.example.SampleTrips.People")
)

let container = ModelContainer(
    for: Trip.self,
    configurations: tripsConfig,
    peopleConfig
)

重要なポイント: -isStoredInMemoryOnlyメモリのみに保存するかどうかを制御します -cloudKitDatabaseCloudKitコンテナ識別子を指定します

  • 複数の構成では、異なるオブジェクト グラフを分離し、それらを個別に保存および同期できます。
  • 読み取り専用モードを設定して機密データを保護できます
  • カスタムファイルURLまたはグループコンテナを指定可能

SwiftUI 統合:modelContainer モディファイア

(06:49) SwiftUI アプリケーションの使用法modelContainerモディファイアはコンテナを作成します。

@main
struct TripsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: Trip.self)
    }
}

重要なポイント: -modelContainer任意のビューまたはシーンに追加可能

  • コンテナの自動変換mainContext環境を注入する -mainContextMainActor は UI シーン専用に調整されていますか

ModelContext: データのメモリ内ビュー

(08:24) ModelContext はデータのメモリ内ビューです。オブジェクトはコンテキストにフェッチされ、編集内容は呼び出されるまでスナップショットとして記録されます。save()そうして初めてそれは長続きすることができます。

// 从环境获取 context
@Environment(\.modelContext) private var context

// 查询数据
@Query private var trips: [Trip]

// 删除操作
func deleteTrip(_ trip: Trip) {
    context.delete(trip)
    // 此时对象仍在 context 中,直到 save()
}

// 保存更改
try? context.save()

重要なポイント: -context.delete()オブジェクトはまだコンテキスト内にあり、削除対象としてマークされているだけです -save()変更は後で ModelContainer に書き込まれ、コンテキストのステータスはクリアされます。

  • オブジェクトはコンテキスト内で参照されている間は存続し、参照が解放された後は自動的にクリーンアップされます。 -rollback()そしてreset()保存されていない変更はクリアできます

元に戻すと自動保存

(09:58) SwiftUImodelContainerモディファイアは、システム全体の取り消しと自動保存をサポートします。

WindowGroup {
    ContentView()
}
.modelContainer(for: Trip.self, isUndoEnabled: true, isAutosaveEnabled: true)

重要なポイント: -isUndoEnabled: trueウィンドウのアンドゥマネージャーをmainContextにバインドします。

  • 3 本指のスワイプおよびシェイク ジェスチャは、コードを追加しなくても元に戻す/やり直しを自動的にサポートします
  • 自動保存はデフォルトで有効になっており、アプリケーションがフロントエンドとバックエンドに入るときに自動的に保存されます。
  • 手動で作成されたコンテキストはデフォルトで自動保存がオフになっています

FetchDescriptor: タイプセーフなクエリ

12:02FetchDescriptorPredicate マクロと組み合わせて、コンパイラで検証されたクエリを実装します。

// 基础查询
let descriptor = FetchDescriptor<Trip>()
let trips = try? context.fetch(descriptor)

// 带条件的查询
let hotelDescriptor = FetchDescriptor<Trip>(
    predicate: #Predicate { trip in
        trip.livingAccommodation?.name == "Grand Hotel"
    }
)

// 带排序和分页
let sortedDescriptor = FetchDescriptor<Trip>(
    predicate: #Predicate { $0.destination == "Paris" },
    sortBy: [SortDescriptor(\.startDate, order: .reverse)],
    offset: 0,
    limit: 20
)

重要なポイント: -#Predicateマクロは Swift クロージャ構文を使用し、コンパイラはプロパティと型を検証します。

  • SwiftData は述語をデータベース クエリに変換します -SortDescriptor任意の属性による並べ替えをサポート -offsetそしてlimitページングの制御

enumerate: 効率的なバッチ トラバーサル

13:19enumerateバッチ トラバーサルのベスト プラクティスをカプセル化します。

try? context.enumerate(FetchDescriptor<Trip>()) { trip in
    // 处理每个 trip
    trip.status = .archived
}

重要なポイント:

  • デフォルトのバッチ サイズは 5000 ですが、カスタマイズできます。
  • バッチ処理と突然変異ガードを自動的に実装 -allowEscapingMutations: trueトラバーサル中にコンテキストを変更できるようにする
  • 大きなデータ オブジェクト (写真やビデオを含む) の場合は、バッチ サイズを削減し、メモリを制御することをお勧めします。

重要ポイント

マルチモジュール アプリケーション用に独立したストレージを構成

  • 対処方法: さまざまな機能モジュールのデータは、独立した ModelConfiguration を使用し、個別に保存および同期されます。
  • 実行する価値がある理由: データを分離して競合を軽減し、モジュールごとに異なる同期戦略を使用できます。
  • 開始方法: 複数の定義ModelConfiguration、異なるものを指定してくださいcloudKitDatabase識別子とファイルの URL

enumerate を使用してビッグ データの移行を処理する

  • 作業内容: 履歴データをバッチで処理します (古いレコードのアーカイブ、統計値の計算など)
  • 実行する価値がある理由:enumerateすべてのオブジェクトを一度にロードしないようにメモリを自動的に管理します。
  • 開始方法: を使用しますcontext.enumerate()データを走査し、バッチ サイズを調整してメモリと I/O のバランスをとります。

バックグラウンド タスク用に独立したコンテキストを作成

  • 内容: ネットワーク同期、バッチ処理、その他のバックグラウンド タスクは独立した ModelContext を使用します。
  • 実行する価値がある理由: メイン スレッドの UI コンテキストのブロックを避け、バックグラウンドの変更が完了した後にメイン コンテキストにマージします。
  • 開始方法: を使用しますModelContext(container)バックグラウンド アクターで操作を実行するための新しいコンテキストを作成する

文字列クエリの代わりに述語マクロを使用します

  • 内容: すべての NSPredicate 文字列クエリを次のように置き換えます。#Predicateマクロ
  • 実行する価値がある理由: コンパイラーは属性の名前と型を検証し、リファクタリング中に自動的に更新し、実行時エラーを回避します。
  • 開始方法: 意志NSPredicate(format: "destination == %@", "Paris")と置き換えます#Predicate { $0.destination == "Paris" }

関連セッション

コメント

GitHub Issues · utterances