🦅

[SwiftUI]SwiftDataでデータを永続化する

2024/05/31に公開

SwiftDataとは

SwiftUIに最適化されたApple純正の永続化フレームワークです。
今回は、SwiftDataを使ってノートアプリを作ってみます。

1. プロジェクト作成

プロジェクトを作成する際に、Storage:の部分でSwiftDataを選ぶと、サンプルコードがついてプロジェクトが作成されます。
今回は、何も指定しないで作成します

2. 構造体の作成

永続化したい構造体を定義します。
import SwiftDataをして
@Modelを付与します。

Note.swift
import Foundation
import SwiftData

@Model
class Note {
    var date: Date
    var text: String

    init(date: Date, text: String) {
        self.date = date
        self.text = text
    }
}

3. モデルコンテナの作成

https://developer.apple.com/documentation/swiftdata/modelcontainer

2で作成したモデルを引数に持たせます。
アプリ内で永続化したいモデルが複数ある場合には下記のように配列で渡します。

.modelContainer(for: [Model1.self, Model2.self])
SwiftDataNoteApp.swift
+ import SwiftData
  import SwiftUI
  
  @main
  struct SwiftDataNoteApp: App {
      var body: some Scene {
          WindowGroup {
              ContentView()
+                 .modelContainer(for: Note.self)
          }
      }
  }

4.永続化したデータの取得

永続化したデータを取得する場合は@Queryを使用します。

@Query private var model: [Model]

Listで一覧を表示してみます。

ContentView.swift
import SwiftData
import SwiftUI

struct ContentView: View {
    @Query private var notes: [Note]

    var body: some View {
        List(notes) { note in
            VStack(alignment: .leading) {
                Text(note.text)
                Text(note.date, style: .date)
                    .foregroundColor(.secondary)
            }
        }
    }
}

5. データの永続化

https://developer.apple.com/documentation/swiftdata/modelcontext/insert(_:)

データの永続化をする場合はinsertメソッドを使用します。

@Environment(\.modelContext) private var modelContext
modelContext.insert(Model)

Noteを新規作成するViewを作成します。

AddNoteView.swift
struct AddNoteView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.modelContext) private var modelContext
    @State private var date: Date
    @State private var text: String

    var body: some View {
        NavigationStack {
            Form {
                DatePicker("日付", selection: $date, displayedComponents: .date)
                    .datePickerStyle(.graphical)

                TextEditor(text: $text)
            }
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("追加") {
                        let newNote = Note(date: date, text: text)
                        modelContext.insert(newNote)
                        dismiss()
                    }
                }

                ToolbarItem(placement: .cancellationAction) {
                    Button("キャンセル", role: .cancel) {
                        dismiss()
                    }
                }
            }
        }
    }
}

AddNoteViewを表示できるように、ContentViewを修正します。

ContentView.swift
  import SwiftData
  import SwiftUI
  
  struct ContentView: View {
      @Query private var notes: [Note]
+     @State private var isShowAddView = false
  
      var body: some View {
+         NavigationStack {
              List(notes) { note in
                  VStack(alignment: .leading) {
                      Text(note.text)
                      Text(note.date, style: .date)
                          .foregroundColor(.secondary)
                  }
              }
+             .sheet(isPresented: $isShowAddView) {
+                 NavigationStack {
+                     AddNoteView()
+                 }
+             }
+             .toolbar {
+                 ToolbarItem(placement: .topBarTrailing) {
+                     Button {
+                         isShowAddView = true
+                     } label: {
+                         Image(systemName: "plus")
+                     }
+                 }
+             }
+         }
      }
  }

Noteが追加できるようになりました。

6. データの変更

SwiftDataはAppStorageと同じように、永続化したデータを自動で更新してくれます。

Noteを@Bindableで受け取って変更できるViewを作成します。

EditNoteView
import SwiftData
import SwiftUI

struct EditNoteView: View {
    @Environment(\.dismiss) private var dismiss
    @Bindable var note: Note

    var body: some View {
        Form {
            Section {
                DatePicker("日付", selection: $note.date, displayedComponents: .date)
            }

            Section {
                TextEditor(text: $note.text)
            }
        }
    }
}

Note一覧のセルをタップしてEditNoteViewに遷移できるように、ContentViewを修正します。

ContentView.swift
  import SwiftData
  import SwiftUI
  
  struct ContentView: View {
      @Query private var notes: [Note]
      @State private var isShowAddView = false
  
      var body: some View {
          NavigationStack {
              List(notes) { note in
+                 NavigationLink {
+                     EditNoteView(note: note)
+                 } label: {
+                     VStack(alignment: .leading) {
+                         Text(note.text)
+                         Text(note.date, style: .date)
+                             .foregroundColor(.secondary)
+                     }
+                 }
              }
              .sheet(isPresented: $isShowAddView) {
                  NavigationStack {
                      AddNoteView()
                  }
              }
              .toolbar {
                  ToolbarItem(placement: .topBarTrailing) {
                      Button {
                          isShowAddView = true
                      } label: {
                          Image(systemName: "plus")
                      }
                  }
              }
          }
      }
  }

Noteを変更できるようになりました。

7. データの削除

https://developer.apple.com/documentation/swiftdata/modelcontext/delete(_:)

データの永続化をする場合はdeleteメソッドを使用します。

@Environment(\.modelContext) private var modelContext
modelContext.delete(Model)

EditNoteViewを修正して、削除ボタンを追加します。

EditNoteView.swift
  import SwiftData
  import SwiftUI
  
  struct EditNoteView: View {
      @Environment(\.dismiss) private var dismiss
+     @Environment(\.modelContext) private var modelContext
      @Bindable var note: Note
  
      var body: some View {
          Form {
              Section {
                  DatePicker("日付", selection: $note.date, displayedComponents: .date)
              }
  
              Section {
                  TextEditor(text: $note.text)
              }
  
+             Section {
+                 Button("削除", role: .destructive) {
+                     modelContext.delete(note)
+ 
+                     dismiss()
+                 }
+             }
          }
      }
  }

Noteを削除できるようになりました。

宣伝

株式会社アルクでは、ディズニー ファンタスピークの開発をしています。
ディズニー ファンタスピークはディズニーの作品や音楽を楽しみながら、英語学習ができるアプリです。
英語を勉強したいけど、教科書みたいなのはちょっと…という方におすすめです。

気になった方は下記からインストールお願いします。

Discussion