開発

SwiftDataとは?@Modelの仕組みとCore Dataとの違い・2026年の採用判断

SwiftDataはAppleがWWDC23で公開した永続化フレームワークで、Swiftのクラスに@Modelを付けるだけでスキーマと保存処理が生成されます。対応OSはiOS 17.0以降、macOS 14.0以降、watchOS 10.0以降、visionOS 1.0以降。内部はCore Dataの実装を土台にしつつ、xcdatamodeldファイルもNSManagedObjectのサブクラスも書かずに済む設計です。この記事では@Modelが生成するもの、ModelContainerとModelContextの分担、最小実装とCRUDの書き方を押さえたうえで、Core Dataから移すべき案件と据え置く案件の線引きまで整理します。

まとめ:SwiftDataの採用判断とCore Dataとの線引き

新規のiOSアプリでオンデバイスにデータを保存するなら、既定はSwiftDataで構いません。モデル定義がSwiftコードに閉じるためレビューと差分管理がしやすく、SwiftUIの@Queryと組み合わせると一覧画面の記述量がCore Data時代の半分以下になります。対象OSをiOS 17以降に引ける案件であれば、選ばない理由が乏しい。

一方、既存のCore Dataアプリを丸ごと書き換える必要はありません。SwiftDataとCore Dataは同一のストア形式を共有でき、片方だけを新機能に使う共存構成が取れます。判断軸は「複雑な述語や集計、細かいフェッチ制御を実装に持っているか」の一点。持っているなら据え置き、単純なCRUDが中心なら移す価値があります。

見送るべき場面もはっきりしています。iOS 16以前を対象に含む、Android版とスキーマを共有したい、数十万件規模の全文検索や集計を端末内で回す。この3つのいずれかに当たるなら、SwiftDataは選択肢から外して構いません。

SwiftDataの定義と@Modelマクロが担う永続化の役割

SwiftDataが宣言的なモデル定義とストア管理を引き受ける範囲

Apple公式ドキュメントはSwiftDataを、モデル化したデータをコードだけで永続化するためのフレームワークと位置づけています。担当するのはスキーマの定義、ストアの生成と読み書き、変更の追跡、そしてSwiftUIへの通知。ネットワーク通信や画面遷移には関与しません。

Core Dataとの関係は置き換えではなく重ね着に近い設計です。ストアの実体は同じSQLiteで、SwiftDataはその上に型安全なSwift APIをかぶせます。だからこそ同一ファイルをCore Data側から開くこともでき、後述する共存構成が成立します。

@Modelマクロがクラスへ自動で付与する4つのプロトコル準拠

@ModelはSwift 5.9で入ったマクロ機能の上に作られており、コンパイル時にクラスへコードを展開します。付与されるのはPersistentModel、Observable、Identifiable、Hashableの4つの準拠。これにより保存対象としての振る舞いと、変更通知の仕組みが同時に手に入ります。

制約は1つ、対象がクラスに限られる点です。構造体には付けられません。マクロが展開する内容はXcodeの「Expand Macro」で読めるため、生成コードを確認したうえで設計を決められます。マクロそのものの言語仕様はSwift 6.2の新機能まとめで押さえておくと、展開結果の読み解きが速くなります。

保存したくないプロパティには@Transientを付けます。計算途中の状態やキャッシュはここで除外しておく。

ModelContainerとModelContextが分担する保存処理の流れ

登場人物は2つです。ModelContainerがストアの実体とスキーマを管理し、ModelContextが編集中の変更を抱えます。アプリ起動時にコンテナを1つ作り、画面ごとにコンテキストから読み書きする。この関係はCore DataのNSPersistentContainerとNSManagedObjectContextにそのまま対応します。

役割 担当すること Core Dataの対応
ModelContainer ストアとスキーマの管理 NSPersistentContainer
ModelContext 変更の保持と保存 NSManagedObjectContext
@Query 取得結果の監視と更新 NSFetchedResults系

SwiftUI側では.modelContainer(for:)を付けた時点で、配下のビューに既定のコンテキストが配られます。明示的にsave()を呼ぶ場面は限られ、通常は自動保存に任せる構成が既定です。

Core Dataとの違いを実装作法とコード量で比較した5つの相違点

xcdatamodeldとSwiftコードで分かれるモデル定義の作法

Core Dataではエンティティと属性をXcodeのGUIエディタで定義し、xcdatamodeldという専用ファイルに保存します。このファイルはXML形式のため、複数人が同じエンティティを触るとマージ衝突が起きやすい。SwiftDataはモデルを普通のSwiftファイルに書くので、この衝突は通常のコード競合として解消できます。

差分レビューの効きも変わります。プロパティを1つ足した変更が、GUIファイルの数十行の差分ではなく1行として見える。受託開発でレビュー工数を見積もる際、ここは実測で効く違いです。

型安全なPredicateとNSPredicateで変わる記述量と検出時期

Core DataのNSPredicateは文字列でフォーマットを書くため、プロパティ名の綴り間違いが実行時まで発覚しません。SwiftDataは#PredicateマクロでSwiftの式をそのまま書き、コンパイル時に型検査が働きます。リネーム時の追従漏れも、ビルドエラーとして先に出ます。

iOS 18からはFoundationの#Expressionマクロが加わり、真偽値以外を返す式を述語の中で組み立てられるようになりました。集計に近い条件を書く場面での回避策が1つ増えた形です。

同一ストアでCore Dataと共存させるときの前提条件と制約

SwiftDataとCore Dataは同じストアファイルを共有できます。条件は、双方のスキーマが完全に一致していること。エンティティ名、属性名、型、リレーションシップの向きまで揃える必要があり、片側だけにプロパティを足すと破綻します。

現実的な使い分けは、既存のCore Dataスタックを残したまま新規画面だけSwiftDataで書く形です。移行を一度に終わらせず、機能追加のたびに置き換え範囲を広げる。この進め方なら、リリースを止めずに移行を進められます。

Core Dataから移行すべき案件と据え置くべき案件の判断軸

移行の価値が出るのは、モデルが単純でCRUDが中心の案件です。マスタデータの保持、お気に入り一覧、下書きの保存。こうした用途ならコード量が減り、新規メンバーの立ち上がりも速くなります。

逆に据え置く判断が妥当なのは、NSFetchRequestの細かい制御を実装に持ち込んでいる場合。バッチ更新、部分フェッチ、複数コンテキストの親子構成を使い込んでいるコードは、SwiftDataに移すと同等の制御ができず遠回りになります。

SwiftDataの最小実装とCRUD・@Queryの記述手順

ModelContainerをApp側へ登録するまでの4つの手順

最小構成は次の順で組み立てます。ここまでで保存先のSQLiteファイルが自動生成され、明示的なパス指定は不要です。

  1. モデルにしたいクラスへ@Modelを付ける
  2. import SwiftDataを対象ファイルに加える
  3. App構造体のWindowGroupへ.modelContainer(for: Item.self)を付ける
  4. ビュー側で@Environment(\.modelContext)を受け取る

保存先を変えたい場合や、メモリ内だけで動かしたいテスト時は、ModelConfigurationでisStoredInMemoryOnlyを指定したコンテナを別途作ります。

insertとdeleteで完結する保存処理と暗黙の保存タイミング

追加はmodelContext.insert(item)、削除はmodelContext.delete(item)。更新に至ってはメソッド呼び出しすら不要で、取得したオブジェクトのプロパティに代入すれば追跡されます。Core Data時代に必要だったNSManagedObjectのサブクラス生成やコンテキストへの明示的な登録は、ここで消えます。

保存の反映は既定で自動です。ただしタイミングはランループに委ねられるため、アプリ終了直前の書き込みや、外部プロセスと同期する処理では明示的にtry modelContext.save()を呼びます。この境界を曖昧にしたまま実装すると、稀にしか再現しないデータ欠落の原因になります。

@Queryのfilterとsortで組み立てる一覧表示の書き方

SwiftUIのビューでは@Queryを宣言するだけで取得と監視が同時に成立します。データが変われば再描画も自動で走るため、ObservableObjectを自作して変更を配る必要がありません。従来@PublishedとPublisherで組んでいた通知経路の考え方はCombineの仕組みを整理した解説と読み比べると差分が見えます。

絞り込みと並べ替えは初期化時に渡します。@Query(filter: #Predicate<Item> { $0.isDone == false }, sort: \Item.createdAt, order: .reverse)のように書けば、未完了のものを新しい順に取得できる。ビューの外で取得したい場合はFetchDescriptorを組み立て、modelContext.fetch(descriptor)を使います。

@Attributeと@Relationshipで指定する一意制約と削除規則

属性の細かい指定は@Attributeで行います。@Attribute(.unique)で重複を禁じ、衝突時は上書き(upsert)になる。画像などの大きなデータには.externalStorageを付け、ストア本体とは別ファイルに逃がします。

関連は@Relationshipで向きと削除規則を決めます。親を消したときに子も消すならdeleteRule: .cascade、参照だけ外すなら.nullify。ここを指定し忘れると孤児レコードが残り、件数の不一致として後から表面化します。

iOS 17から27世代までSwiftDataに入った機能の変遷

iOS 18で加わった#Unique・履歴API・カスタムデータストア

WWDC24の更新は地味ながら実務への影響が大きい内容でした。複数プロパティの組み合わせに一意制約をかける#Unique、変更履歴を追跡する履歴API、そしてDataStoreプロトコルによるカスタムデータストアの3つ。

履歴APIはサーバー同期を自前で書く案件で効きます。どのレコードがいつ追加・更新・削除されたかを取得できるため、差分だけを送る同期処理が組めるようになりました。カスタムデータストアはSQLite以外、たとえばJSONファイルやリモートAPIをSwiftDataの裏側に据える仕組みで、既存バックエンドを持つ受託案件で選択肢になります。

iOS 26で入ったクラス継承とスキーマ移行時に増えた3つの注意点

WWDC25の主題はモデルのクラス継承でした。共通のプロパティを基底クラスに置き、サブクラスで拡張する設計がスキーマとして扱えるようになり、種別ごとに似たモデルを並べる必要がなくなりました。

ただし移行側の注意が増えています。継承を含むスキーマは基底クラスとすべてのサブクラスに@available注記が必要で、注記漏れは旧OS上での不整合につながる。移行自体は軽量移行として扱われますが、旧バージョンからのアップグレード経路はiOS 26以降の実機で通しの検証が要ります。既存アプリに継承を後から入れる場合、この検証工数を見積もりに入れておく。

WWDC26で追加された区切り取得と非SwiftUI向け監視API

WWDC26のセッション「What’s new in SwiftData」では、追加された4点が示されました。提供は2026年秋のOS世代向けとされています。

API 解決すること
@Query(sectionBy:) 取得結果の区切り分け
@Attribute(.codable) 他社型の保存
ResultsObserver ビュー外での取得と監視
HistoryObserver 履歴変更の通知受け取り

@Attribute(.codable)には明確な制約があります。値はシリアライズ済みのデータとして格納されるため、述語での絞り込みにも並べ替えにも使えない。型の形が変わっても移行が起動しないので、前方・後方互換をCodable実装側で担保する必要があります。自作の型ではなく、手を入れられない外部ライブラリの型を保存したいときの逃げ道として使う、というのがセッションでの位置づけです。

新規iOSアプリでSwiftDataを採用する条件と見送る場面

SwiftDataを既定の永続化層に置いてよい案件の3つの条件

採用してよいと判断できるのは次の条件が揃う場合です。対象OSをiOS 17以降に引ける、UIがSwiftUI中心である、保存するデータが端末内で完結するかCloudKit同期で足りる。この3つを満たす新規案件なら、Core Dataを選び直す理由はほぼありません。

コード量の差は無視できない規模になります。エンティティ1つの追加・一覧・削除をひととおり書いた場合、Core Data構成で必要だったスタック初期化とフェッチリクエストの記述が消え、実装は@Modelのクラス定義と@Query1行に収まる。学習コストの回収も早い。

SwiftDataを見送りCore Dataを選ぶべき3つの場面

見送りを勧めます。対象OSにiOS 16以前が含まれる案件、NSFetchRequestの細かい制御に依存している既存アプリ、そして複数のバックグラウンドコンテキストを親子で組んで大量書き込みを捌いている構成。この3つでは、SwiftDataに寄せると同等の制御が書けず、遠回りな回避策が積み上がります。

判断を保留にしないでください。「新しいから」で採用して、後からフェッチ制御が足りないと分かる差し戻しが、移行案件で最も痛い。着手前に既存コードのNSFetchRequestを数え、10箇所を超えて細かいオプション指定があるなら据え置きが妥当です。

RealmやSQLiteと比べてSwiftDataが不利になる条件

SwiftDataが不利になる条件は2つに絞られます。1つはクロスプラットフォーム、もう1つは大量データの検索性能です。AndroidとiOSでスキーマや同期の仕組みを揃えたい案件では、Apple製フレームワークである時点で候補から外れます。Realmの採用判断を整理した解説と突き合わせて、どちらの制約が案件に効くかで決めるのが実務的です。

性能面では、数十万件を跨いだ集計や全文検索を端末内で回す要件になると、SQLiteを直接叩く設計に軍配が上がります。SwiftDataは述語をSQLへ変換しますが、インデックス設計や実行計画の細かい制御までは開けていません。

SwiftData導入でつまずく失敗パターンと保守体制の判断軸

VersionedSchemaを後回しにして詰まる移行時の典型パターン

最も多い詰まり方は、初回リリースでスキーマのバージョン管理を省いてしまうことです。@Modelだけで動いてしまうため、VersionedSchemaとSchemaMigrationPlanを書かないまま出荷できる。次のリリースでプロパティを1つ足した瞬間、既存ユーザーの端末で起動時にクラッシュします。

初回からVersionedSchemaで版を切り、移行計画を空でも定義しておく。この一手間を省いた分は、後から数倍の工数で戻ってきます。プロパティのリネームは軽量移行では追従しないため、@Attribute(originalName:)での指定も併せて習慣にしておく。

バックグラウンド処理とModelActorで起きる並行性の落とし穴

ModelContextはスレッド安全ではありません。バックグラウンドで取得したモデルをそのままメインスレッドのビューに渡す実装は、Swift 6の厳格な並行性チェックでコンパイルを通りません。正しい経路は@ModelActorを付けたアクターの中で処理し、境界を越えるときはPersistentIdentifierだけを渡してから受け側で取得し直す形です。

ここを場当たりに@unchecked Sendableで黙らせると、実機でのみ再現するデータ破損に化けます。並行性の警告は握り潰さない。

iOSアプリの永続化層を外注へ任せるときの体制と引き継ぎ基準

永続化層は、内製と外注の境界を引きにくい領域です。画面は内製しつつデータ層だけ外部に任せる分担は成立しますが、その場合はスキーマの版管理と移行計画の責任範囲を契約時に明記しておく必要があります。移行の失敗はユーザーのデータ消失に直結するため、後から責任の所在を決めると揉めます。

引き継ぎの基準は3つ。VersionedSchemaの版履歴が残っていること、移行のテストが旧版のストアファイルを使って自動化されていること、ModelActorの境界がコードで示されていること。既存Core Dataアプリの移行を含む案件は、この検証工数の見積もりで差が出ます。iOSアプリ開発の受託では移行経路の検証とスキーマ設計を含めて対応しており、既存アプリの棚卸しから相談できます。発注側の全体像はiOSアプリ開発の費用と外注判断の解説も参照してください。

よくある質問

SwiftDataの採用検討でよく挙がる質問を、実装と発注の両面から5つ整理します。

SwiftDataはCore Dataを置き換えるものですか?

置き換えではありません。SwiftDataはCore Dataの実装を土台にした上位レイヤーで、2026年8月時点でAppleはCore Dataの廃止を予告していません。両者は同一ストアを共有する共存構成も取れます。新規案件の既定をSwiftDataに寄せ、細かいフェッチ制御が要る箇所だけCore Dataを残す。この線引きが現実的です。

SwiftDataはiOS 16以前の端末でも使えますか?

使えません。SwiftDataの対応はiOS 17.0以降、iPadOS 17.0以降、macOS 14.0以降、tvOS 17.0以降、watchOS 10.0以降、visionOS 1.0以降です。iOS 16以前を対象に含む案件では、Core Dataかサードパーティのライブラリを選ぶことになります。対象OSの下限は要件定義の段階で確定させておく必要があります。

SwiftDataでiCloud同期はできますか?

できます。ModelConfigurationでCloudKitのコンテナを指定すれば、端末間の同期が動きます。ただし制約があり、CloudKit同期を有効にする場合はすべてのプロパティに初期値が必要で、@Attribute(.unique)による一意制約も使えません。同期を前提にするなら、モデル設計の段階でこの2点を織り込んでおきます。

SwiftDataの学習にはどのくらいかかりますか?

SwiftUIの経験がある実装者なら、@Model@Queryで基本的なCRUDを書けるようになるまでは1日程度。難所はその先で、スキーマ移行の設計、ModelActorを使った並行処理、CloudKit同期の制約回避には相応の期間がかかります。移行を含む既存アプリの改修では、この後半部分が工数の大半を占めます。

Core DataからSwiftDataへ移行する手順はどうなりますか?

一括変換ではなく段階移行を勧めます。既存のxcdatamodeldと完全に一致する@Modelクラスを定義し、同一ストアを共有した状態で新規画面だけSwiftData側から読み書きする。動作を確認しながら対象範囲を広げ、最後にCore Dataスタックを外します。エンティティ名や属性名が1つでもずれると読めなくなるため、既存モデルの棚卸しが最初の作業になります。

関連記事

資料請求

RELATED POSTS 関連記事