🤝
SwiftDataの@Relationshipの使い方
SwiftDataって何?
こちらの記事が大変参考になります!
@Relationship
Model同士を自動で連携してくれるらしいので、便利そう。
使い方
今回は実装例として、Todoアプリを想定したコードを記載します。
Modelの作成
@Model
final class Task: Identifiable {
@Attribute(.unique) var id: UUID
var name: String
// @Relationshipをつけて明示的に繋げる
@Relationship(inverse: \ChildTask.parent)
var childTasks: [ChildTask]
init(
id: UUID = .init(),
name: String,
childTasks: [ChildTask] = []
) {
self.id = id
self.name = name
self.childTasks = childTasks
}
}
@Model
final class ChildTask: Identifiable {
var name: String
var isDone: Bool
var parent: Task
init(
name: String,
isDone: Bool = false,
parent: Task
) {
self.name = name
self.isDone = isDone
self.parent = parent
}
}
Modelの初期化
@main
struct SampleTodoApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Task.self,
ChildTask.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)
}
}
Viewの作成
tasksにデータを保存する部分は、今回の@Relationship
を説明する上では省略させていただきます。
↓すでにtasks: [Task]
に一つ以上データが入っている想定
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query var tasks: [Task]
var body: some View {
VStack {
List {
ForEach(tasks, id: \.id) { task in
// サンプルのためnilを考慮していません
let childTask = tasks.childTasks.first
HStack {
Text(tasks.name)
Text("\(childTask?.isDone)")
Spacer()
Button(action: {
onTapButton(task: task)
}) {
Text("更新")
}
}
}
}
}
}
private func onTapButton(task: Task) {
let isCompleted = true
// または let isCompleted = false
let newChildTask = ChildTask(
name: "子タスク",
isCompleted: isCompleted,
// ここで紐付ける!!
task: task
)
modelContext.insert(newChildTask)
do {
try modelContext.save()
} catch {
// エラー処理
}
}
}
さいごに
不備・間違い等あればご指摘いただけると幸いです。
Discussion