本記事では、
- Core Data データベースを既存の SwiftUI アプリケーションに追加する方法を紹介します。
-
NSMergePolicy
を使用したコアデータデータベースのマージ競合の管理方法についても説明します。
Core Dataモデルファイルとクラス定義の作成
モデルファイルとクラス定義用のコードファイルの作成の方法はこちらの通りです。これに関しては過去記事の1つで紹介済みです。
最初に、データモデルファイルを作成します。キーボードのcommand-Nキーを押して、 新しい To-Doアイテムごとに次のプロパティを格納するTo-Doアプリを作成するとします: 作成した新しいアイテムをダブルクリックし、名前を付けるだけです。この例では、 ここでは、To-Doアプリに次のプロパティが必要です。 タイプを設定するには、プロパティ名の横にあるドロップダウンメニューをクリックします: このような感じになります。 以前の設定: 新しい設定: 最上部のメニューで こうしたサブクラスを生成することで、 ファイルナビゲーターに以下のファイルが表示されます :詳細に関してはこちらをクリックしてください
Data Model
を検索します。Data Model
にあなたのアプリの名前をつけてください。例えば、ここでは私のアプリの名前は CoreDataDemo
なので、私は CoreDataDemo.xcdatamodeld
を作りました。
データベース構造の作成
1.
.xcdatamodeld
ファイルを開き、Add Entity
をクリックします。
作成した新規エンティティ・アイテムに
TodoItem
という名前を付けます。TodoItem
という名前を付けます。
新しいプロパティを追加する
Properties
セクションのプラスアイコンをクリックして、新しいプロパティを追加します。
プロパティ名
タイプ
todoTaskName
String
personName
String
taskDueTime
Date
Entity クラスのコードファイルを生成
Codegen
設定を Manual/ None
に変更
Editor
をクリックし、Create NSManagedObject subclass...
をクリックしますTodoItem
を新規オブジェクトの作成に直接使用できるようになります。
データベースマネージャーを作成する
現在、コアデータベースに関連する関数を含む新規ファイルを作成できるようになっています。
このファイルで、NSPersistentCloudKitContainer
をご利用のデータベース名で初期化することになります。
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init() {
container = NSPersistentCloudKitContainer(name: "CoreDataDemo")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
print(error.localizedDescription)
}
})
}
}
その後、メインのSwiftUIアプリファイル(@main
というコードから始まるファイル)で、PersistenceController
の共有インスタンスを初期化できます。
@main
struct SimpleTODOApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
SceneDelegate
を使っている場合には、SceneDelegate.swift
ファイルにおいて、コードを scene
関数に追加してください。SwiftUI
と CoreData
フレームワークのインポートをお忘れなく。
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let context = PersistenceController.shared.container.viewContext
let contentView = ContentView()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
.environment
を追加
これで、PersistenceController.shared
がすでに初期化されているので、ルートSwiftUIビューの環境変数を設定する必要があります。
まず、コンテンツビューを初期化するファイルにこの行を追加します。
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
そして、この変数をコンテンツビュー ContentView
の最上部に追加します:
@Environment(\.managedObjectContext) private var viewContext
これで、コンテンツビューがデータベースにアクセスできるようになります。
FetchRequestを追加する
データベースからコンテンツをフェッチするには、FetchRequest
を作成します。
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \TodoItem.taskDueTime, ascending: true)],
animation: .default)
private var items: FetchedResults<TodoItem>
上記のコード例では、TodoItem.dueTime
に基づいて項目をソートしています。それを自分のプロパティ名に変更する必要があります。
keyPath
変数のフォーマットを[データベースエンティティの名前].[選択したエンティティの変数名]にする必要があります。
これで、アイテムをテーブルに表示できます。データベース内の項目が変更されると、テーブルは自動的に更新されます。
その他のSwiftUIビューの環境の準備
初期化する各ビューに対してこのステップを繰り返して環境を準備することが重要です。
例えば、ToDoItemCreate
というビューがあるなら、ToDoItemCreate
ビューを初期化する際にはこの行を追加する必要があります。
ToDoItemCreate(isShown: $showTodoCreateView)
.environment(\.managedObjectContext, self.viewContext)
また、変数 viewContext
を ToDoItemCreate
ビューに追加する必要があります。
@Environment(\.managedObjectContext) private var viewContext
データベースのコンフリクトへの対応
データベースが自身に変更を書き込もうとする際には、コンフリクトが発生することがあります。(例えばオブジェクトの重複など。)
デフォルトで、Core Data
フレームワークは例外を発生させます。
viewContext
の mergePolicy
プロパティーを設定することで、コンフリクトの解消を試みることができます。
self.viewContext.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType)
以下は一部の結合ポリシーの説明です。
Name | Explanation |
---|---|
NSErrorMergePolicyType | デフォルト。try viewContext.save() を呼び出すと、例外が報告されます。 |
NSMergeByPropertyStoreTrumpMergePolicyType | メモリ内の変更は外部変更を置き換えます |
NSMergeByPropertyObjectTrumpMergePolicyType | 外部変更はメモリ内の変更を置き換えます。 |
NSOverwriteMergePolicyType | メモリ内のオブジェクト全体が永続ストアにプッシュされます。 |
NSRollbackMergePolicyType | 対立する変更されたオブジェクトについて、すべての状態が破棄されます |
通常、NSMergeByPropertyObjectTrumpMergePolicy
を使用すると、Core Data
はデータベースのデータバージョンを新しい変更で自動的に上書きします。