🪶

CoreDataを使う

2024/09/04に公開

CoreDataは、いまだに人気がある

https://developer.apple.com/documentation/coredata/

Core Data
Persist or cache data on a single device, or sync data to multiple devices with CloudKit.

Overview
Use Core Data to save your application’s permanent data for offline use, to cache temporary data, and to add undo functionality to your app on a single device. To sync data across multiple devices in a single iCloud account, Core Data automatically mirrors your schema to a CloudKit container.

Through Core Data’s Data Model editor, you define your data’s types and relationships, and generate respective class definitions. Core Data can then manage object instances at runtime to provide the following features.

コア・データ
CloudKitを使用して、1つのデバイスにデータを永続化またはキャッシュしたり、複数のデバイスにデータを同期したりできます。

概要
Core Data を使用すると、アプリケーションの永続的なデータをオフラインで使用できるように保存したり、一時的なデータをキャッシュしたり、1 つのデバイス上のアプリケーションにアンドゥ機能を追加したりできます。1つのiCloudアカウントで複数のデバイスにわたってデータを同期するために、Core DataはCloudKitコンテナにスキーマを自動的にミラーリングします。

Core Dataのデータモデルエディタを通じて、データの型とリレーションシップを定義し、それぞれのクラス定義を生成します。Core Dataは実行時にオブジェクトインスタンスを管理し、以下の機能を提供します。

標準機能で入ってる。設定は意外と難しくない???。久しぶりに触ってみた。昔は、UIKitで使いましたね。

この動画見れば参考になった

https://www.youtube.com/watch?v=UxSYXRQ82xM

モデルの設定

import CoreData

struct PersistentController {
    let container: NSPersistentContainer
    
    init() {
        container = NSPersistentContainer(name: "MyCoreData")
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolve error \(error)")
            }
        })
    }
}

エントリーポイントに設定

import SwiftUI

@main
struct CoreDataTutorialApp: App {
    let persistenceController = PersistentController()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

アプリのコード

少しアレンジしてみた。チェックしたデータだけ削除するリマインダーアプリのタスク機能のようなものにした。

import SwiftUI
import CoreData

struct ContentView: View {
   @Environment(\.managedObjectContext) private var viewContext
   
   @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Human.name, ascending: true)])
   private var humans: FetchedResults<Human>
   
   @State private var name = ""
   
   var body: some View {
       VStack {
           HStack {
               TextField("人間の名前", text: $name)
               Button(action: addHuman) {
                   Text("保存")
               }
           }
           .padding()
           
           List {
               ForEach(humans) { human in
                   HStack {
                       Button(action: { toggleChecked(human) }) {
                           Image(systemName: human.checked ? "checkmark.square" : "square")
                       }
                       Text(human.name ?? "")
                   }
               }
           }
           
           Button(action: deleteCheckedHumans) {
               Text("チェックした項目を削除")
           }
           .padding()
       }
   }
   
   private func addHuman() {
       withAnimation {
           let newHuman = Human(context: viewContext)
           newHuman.name = name
           newHuman.checked = false
           
           saveContext()
           name = ""
       }
   }
   
   private func toggleChecked(_ human: Human) {
       withAnimation {
           human.checked.toggle()
           saveContext()
       }
   }
   
   private func deleteCheckedHumans() {
       withAnimation {
           humans.forEach { human in
               if human.checked {
                   viewContext.delete(human)
               }
           }
           
           saveContext()
       }
   }
   
   private func saveContext() {
       do {
           try viewContext.save()
       } catch {
           let nsError = error as NSError
           fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
       }
   }
}

動作はこんな感じ


まとめ

最近は、SwiftDataを使っているのですが、古いOSにも対応するアプリを作るとなると、サポートされているCoreDataを選択すると思うので、こちらの方が良いでしょう。

Discussion