🙆

Core DataをSwiftUIと連携させる手順

2022/02/21に公開

下記のようなデータをCore Dataで作り、そしてSwiftUIと連携させる手順を記録します

struct Strudent {
    var id: UUID
    var name: String
}

XcodeでSwiftUIプロジェクトを作り、プロジェクト名と「Bookworm」にします

Data Model

まずは cmd + Nでファイルを新しく作ります

ファイルタイプは「Data Model」を選択、名前は「Bookworm」にします

次は「Add Entity」をクリック

左の「Entity」をダブルクリックして、「Student」へ改名します

Attributeの「+」をクリック、Attribute名は「id」、Typeは「UUID」

もう一回にAttributeを作ります。Attribute名を「id」、Typeを「String」

Swift Data Controller

新しいファイル「DataController.swift」を作ります

CoreDataをインポートします

DataController.swift
+import CoreData
 import Foundation

コントローラーのクラスを定義する

DataController.swift
import CoreData
import Foundation

+class DataController: ObservableObject {
+    
+}

ObservableObjectを利用して、そのデータがアプリが起動と同時にアクティブ状態に入り、そしてアプリが落ちてない限りにそのデータがずっとアクティブの状態のままです

containerを定義

DataController.swift
import CoreData
import Foundation

class DataController: ObservableObject {
+    let container = NSPersistentContainer(name: "Bookworm")
}

nameは先ほど作ったDate Modalと同じようにします

最後にロードエラーを備えて以下を書きます

DataController.swift
import CoreData
import Foundation

class DataController: ObservableObject {
     let container = NSPersistentContainer(name: "Bookworm")
    
+    init() {
+        container.loadPersistentStores { description, error in
+            if let error = error {
+                print("Core Data failed to load: \(error.localizedDescription)")
+            }
+       }
    }
}

BookwormApp.swift

を開けて、以下のコードを書きます

BookwormApp.swift
import SwiftUI

@main
struct BookwormApp: App {
+    @StateObject private var dataController = DataController()
    
     var body: some Scene {
        WindowGroup {
            ContentView()
        }
     }
}

environment modifierを加える

BookwormApp.swift
struct BookwormApp: App {
    @StateObject private var dataController = DataController()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
+                .environment(\.managedObjectContext, dataController.container.viewContext)
        }
    }
}

ContentView.swift

@FetchRequestを使ってCore Dataにデータをリクエストします、そしてUIにシンクロさせる

ContentView.swift
struct ContentView: View {
+    @FetchRequest(sortDescriptors: []) var students: FetchedResults<Student>
    
     var body: some View {
        Text("2")
     }
}

データを表示させます

ContentView.swift
struct ContentView: View {
    @FetchRequest(sortDescriptors: []) var students: FetchedResults<Student>
    
    var body: some View {
        VStack {
+            List(students) { student in
+                Text(student.name ?? "Unknown")
+            }
        }
    }
}

データを追加するために

まずは@Environment()を使って、Core Dataの上層クラスにデータへのアクセスをリクエストします

ContentView.swift
struct ContentView: View {
+    @Environment(\.managedObjectContext) var moc
+    @FetchRequest(sortDescriptors: []) var students: FetchedResults<Student>
    
    var body: some View {
        VStack {
            List(students) { student in
                Text(student.name ?? "Unknown")
            }
        }
    }
}

追加する情報を作って追加する

ContentView.swift
struct ContentView: View {
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(sortDescriptors: []) var students: FetchedResults<Student>
    
    var body: some View {
        VStack {
            List(students) { student in
                Text(student.name ?? "Unknown")
            }
            
+            Button("Add") {
+                let firstNames = ["Ginny", "Harry", "Hermione", "Luna", "Ron"]
+                let lastNames = ["Granger", "Lovegood", "Potter", "Weasley"]
+                
+                let chosenFirstName = firstNames.randomElement()!
+                let chosenLastName = lastNames.randomElement()!
+                
+                let student = Student(context: moc)
+                student.id = UUID()
+                student.name = "\(chosenFirstName) \(chosenLastName)"
+
+		 try? moc.save()
+            }

        }
    }
}

Discussion