はじめに
SwiftDataにチェックを入れてプロジェクトを開始するとサンプルコードが生成される.
このときinsertやdeleteはModelContextを必要とするため,Viewの中に記述されている.これではView以外の場所でDataを扱うことができなくなる.
初めての記事投稿になるので,簡単な内容を投稿する.
この記事でわかること
SwiftDataをView以外の場所で使えるようになる.
詳細
1. 基本方針
- データを操作するクラスを実装する
- ModelContextデータを操作する関数の引数として受け取る
2. 詳細実装(App)
SwiftData_Qiita_testApp.swift
@main
struct SwiftData_Qiita_testApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Item.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
- 共有用のModelContainerを作成する
- Schema: データ構造を決定する
- ModelConfiguration: データの保存に関する設定を行う
- これらを元にModelContainerを作成する
- ContentViewにModelContainerを渡す
- ViewでSwiftDataを使うためには必ず渡す必要がある
3. 詳細実装(Model)
Item.swift
@Model
final class Item {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
class ItemDatastore {
// シングルトン
@MainActor static let shared = ItemDatastore()
func insert(modelContext: ModelContext, timestamp: Date) {
modelContext.insert(Item(timestamp: timestamp))
try? modelContext.save()
}
func delete(modelContext: ModelContext, item: Item) {
modelContext.delete(item)
try? modelContext.save()
}
}
- 今回扱うデータ構造を定義する
- データ構造のクラスには@Modelをつける
- データ操作を行うクラスを実装する
- シングルトンで実装する
- insert, delete関数を実装する
- どちらも引数にModelContextを受け取る
4. 詳細実装(ContentView)
ContentView.swift
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
NavigationLink {
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
} label: {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
.onDelete(perform: deleteItems)
}
...
}
private func addItem() {
withAnimation {
let newItem = Item(timestamp: Date())
// modelContext.insert(newItem)
ItemDatastore.shared.insert(modelContext: modelContext, timestamp: newItem.timestamp)
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
// modelContext.delete(items[index])
ItemDatastore.shared.delete(modelContext: modelContext, item: items[index])
}
}
}
}
- データ操作を行う場合はmodelContextが必要である
ContentView.swift
@Environment(\.modelContext) private var modelContext
- リアルタイムでデータを取得する場合は@Queryを使う
- このように宣言された変数はデータが変更されると自動的に更新される
ContentView.swift
@Query private var items: [Item]
- データ操作を行う関数を呼び出す際は,引数にmodelContextを渡す
- これによりView以外の場所でデータ操作を行うことができる
ContentView.swift
ItemDatastore.shared.insert(modelContext: modelContext, timestamp: newItem.timestamp)
ここで紹介したコード
https://github.com/k22036/SwiftData-Qiita-test
まとめ
View以外の場所でSwiftDataを使う方法を紹介した.
ModelContextを引数に受け取ることで,View以外の場所でデータ操作を行うことができる.