
SwiftDataでデータを扱う上で欠かせない存在が ModelContext です。
これはアプリ内のデータを保存・変更・削除するときの「作業スペース」や「窓口」と言える役割を持っています。
この記事では、ModelContextの意味や基本的な使い方、注意点までなるべくわかりやすく解説します。
ModelContextとは?
SwiftDataにおける ModelContext は、データを保存したり読み書きするための「コンテナ」的な存在です。
例えば、テキストを入力して保存する、リストにアイテムを追加する、既存データを削除する ―― これらすべての操作は ModelContext を通じて行います。
イメージとしては、「データベースに直接触らず、まずはContextに変更を加えてから、それを保存する」 という流れです。
Core Data でいうところの NSManagedObjectContext に近い位置づけです。
具体例:新しいデータを追加する
ここでは「新しいデータを追加する」というシンプルな例を通じて、基本的な流れを理解してみましょう。
ユーザーがメモを入力し、それを保存・表示する仕組みを実装していきます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import SwiftUI import SwiftData @Model class Memo { var text: String init(text: String) { self.text = text } } struct ContentView: View { @Environment(\.modelContext) private var context @Query private var memos: [Memo] @State private var inputText = "" var body: some View { VStack { TextField("メモを入力", text: $inputText) .textFieldStyle(.roundedBorder) .padding() Button("保存") { let newMemo = Memo(text: inputText) context.insert(newMemo) // データをContextに追加 try? context.save() // 永続化 inputText = "" } List(memos) { memo in Text(memo.text) } } } } |
コードのポイント
@Environment(\.modelContext)で現在の ModelContext を取得- TextFieldに入力した文字列を
Memoモデルとして作成 context.insert()でデータをContextに追加context.save()で実際に保存(永続化)
この仕組みにより、ユーザーが入力したメモはModelContextを通じて永続化され、アプリの再起動後も保持されます。
ModelContextの取得方法
ModelContextの代表的な取得方法と使い分けを解説します。
標準の取得方法
|
1 2 |
@Environment(\.modelContext) private var context |
特別な初期化処理が不要な場合は、この方法で十分です。
他の取得方法
View初期化時に直接渡す
|
1 2 3 4 5 6 7 8 |
struct ContentView: View { let context: ModelContext init(context: ModelContext) { self.context = context } } |
ModelContextを明示的に受け取る方法です。
依存関係を注入する形になるため、特殊な初期化処理やプレビュー用のテストデータ注入に役立ちます。
ModelContextを直接作成
|
1 2 3 |
let container = ModelContainer(for: Memo.self) let context = ModelContext(container) |
ここではModelContainerを自前で生成し、それを使ってModelContextを作ります。
この方法は以下のようなケースで便利です。
- ユニットテスト環境(専用のデータベースを使いたい場合)
- デバッグツール用の画面
- 本番アプリとは異なる小規模なデータセットを使う場合
StateObjectとして管理
|
1 2 3 4 5 6 7 8 |
class DataManager: ObservableObject { let context: ModelContext init() { let container = ModelContainer(for: Memo.self) self.context = ModelContext(container) } } |
この方法は、アプリ全体で共通のContextを使いたい場合に有効です。
例えば:
- ユーザー情報や設定データなど、全画面で一貫して利用する必要があるデータ
- 複数のViewにわたってContextを共有したい場合
DataManagerを@StateObjectとして@mainのルートで保持し、.environmentObject(dataManager) の形で子Viewに渡すことで、全ての画面で同じModelContextを利用できるようになります。
これにより、「どの画面でも同じデータが見えている」状態を自然に実現できます。
大規模なアプリやマルチスクリーンのアプリでは、このパターンが推奨されるケースが多いです。
ModelContextの主要メソッド
ModelContextの主要メソッドは下記のとおりです。
| メソッド | 説明 |
|---|---|
insert(_:) |
新しいデータを追加 |
delete(_:) |
既存データを削除 |
save() |
Context内の変更を永続化(実際の保存処理) |
rollback() |
保存前の変更を取り消す |
- insert(_:)
新しいオブジェクトを作成したときに、context.insert(newData)のように呼び出します。保存はまだされておらず、save()を呼ぶことで初めて永続化されます。 - delete(_:)
context.delete(object)と指定することでデータを削除対象にします。こちらも、save()を呼ぶまでは実際のデータベースからは消えません。 - save()
insertやdeleteで加えた変更を確定してデータベースに反映します。アプリ終了後も保持されるようになります。 - rollback()
保存前に行った変更をすべて取り消します。例えば、入力フォームでユーザーが一度「保存」ボタンを押したものの、処理中にエラーが発生した場合に使えます。-
このようにすることで、中途半端な変更がデータベースに残らないようにできるのがメリットです。1234567do {try context.save()} catch {context.rollback() // 保存前の状態に戻すprint("保存失敗: \(error)")}
-
ModelContextを使うときの注意点
SwiftDataのModelContextは便利に使える反面、いくつかの注意点を押さえておかないと、意図した通りにデータが保存されなかったり、予期せぬ挙動につながることもあります。
-
save()を忘れずに呼ぶinsertやdeleteを呼んでも、その時点ではまだ変更は反映されません。必ずsave()を実行して初めて永続化されます。これを忘れるとデータが消えたり、アプリ再起動で失われてしまいます。 -
複数のContextを使い分けられることを理解しておく
テスト用・プレビュー用に独自のModelContextを生成したり、画面ごとに異なるコンテキストを渡したりできます。これにより、本番データと分離した安全な操作が可能です。 -
エラーハンドリングを適切に行う
try context.save()のように保存処理は失敗する可能性があります。その際はcatch内でrollback()を呼ぶことで、保存前の状態に戻してデータの整合性を保つことができます。
まとめ
今回はSwiftDataを使う時に重要な「ModelContext」について解説しました!
- ModelContextはデータ操作の作業スペース
- 標準は
@Environment(\.modelContext)を使う - 必要に応じて「直接渡す」「独自生成」「StateObjectで保持」といった方法もある
insert/delete/saveを組み合わせて基本的なCRUD操作を行える
SwiftDataを扱う上でModelContextの理解は不可欠です。
ModelContextを理解してSwiftDataを自在に操れるようになるとアプリ開発時にできることが大きく広がります!
是非活用してみてくださいね!
