【SwiftUI】Core Dataの使い方:標準テンプレートを読み解く

SwiftUIでのCore Dataの使い方を、標準テンプレートを読み解きながら解説します。

スポンサーリンク

環境

この記事の情報は次のバージョンで動作確認しています。

【Xcode】12.3
【Swift】5.3.2
【iOS】14.3
【macOS】Big Sur バージョン 11.1
スポンサーリンク

標準テンプレートの生成

Xcodeで新規プロジェクトを生成します。

InterfaceはSwiftUIを選択
Life CycleはSwiftUI Appを選択
Use Core Dataにチェックを入れて下さい。

標準テンプレートの生成

標準でCore Dataを利用したアプリのテンプレートコードが生成されます。

スポンサーリンク

標準テンプレートを動かす

生成されたテンプレートをシミュレータで実行しても、ただ真っ白の画面が表示されるだけで何もできません。
テンプレートのコードが中途半端なのが理由なのですが、なぜAppleがそれを放置しているのかは不明です。
まずはContentViewのbody部を次のように修正し下さい。

修正後シミュレータを実行すると、Editボタンと+ボタンが画面上に追加され、+ボタンでリストの行追加、Editボタンでリストの編集(削除のみ)が可能になります。
一旦アプリを終了してから再度立ち上げても、リストには前の状況が残っており、永続的なデータ保存が実現が確認できます。

標準テンプレートを動かす

次章以降で、標準テンプレートの詳細について解説します。

スポンサーリンク

データモデルの定義

Core Dataで扱うデータモデルは、プロジェクト名.xcdatamodeldファイルで定義されています。
下図の「エンティティ名」がDBのテーブル名、「属性情報」がテーブルのカラム情報に相当します。
標準テンプレートでは、属性項目timestampを1つだけ持つ、 Itemテーブルが定義されています。

データモデルの定義

このデータモデル定義に従って、Itemクラスが生成されます。
Itemクラスはテーブルの1レコードを格納するクラスで、エンティティの基本クラスである被管理オブジェクト(NSManagedObject)を継承しています。

デフォルトの設定では、ItemクラスのソースコードはXcode上見えません。

スポンサーリンク

リストの表示処理

データベースからデータを取得して、リストに表示する処理は、ContentViewの前半に記述されています。
わかりやすいようにコメントを追加しました。

被管理オブジェクトコンテキスト(ManagedObjectContext)の取得

被管理オブジェクトコンテキスト(ManagedObjectContext)はデータの生成、保存、取得といったデータベース操作に必要な操作を行う為のオブジェクトです。
このオブジェクトを使ってデータベースアクセスする全ての操作を行います。
ManagedObjectContextはアプリ起動時に生成され、環境変数managedObjectContextに登録されています。

データベースよりデータを取得(Fetch処理)

プロパティラッパーの@FetchRequestを使ってデータベースを検索し、対象データ群をitemsプロパティに格納しています。
引数(sortDescriptors)で検索結果のソート条件(Itemテーブルのtimestamp属性が昇順)を指定、
引数(animation)で取得した検索結果の変更時に使用されるアニメーションタイプを.defaultに指定しています。

取得結果が格納されるitemsは被管理オブジェクト(ManagedObject)のコレクションであるFetchedResults<Item>型です。
ManagedObjectはテーブルの1レコードに該当するエンティティを保持するクラスで、ObservableObjectに準拠している為、値の変更がSwiftUIのViewと同期します。

取得したデータをリスト表示

検索結果itemsの各レコードを、TextビューとしてListに表示しています。
item.timestampの出力形式を、formatterで指定していますが、これはSwiftUIで新たに追加されたLocalizedStringKey型で使えるようになった記述方法です。
なお、出力形式を示すitemFormatterは同じファイル内で次のように定義されています。

.onDelete()はForEachのModifierで、コレクション(配列)から要素を削除する時に呼び出す処理を指定します。

ナビゲーションバーの設定

ナビゲーションバーの左側にEditボタン、右側に+ボタンを設定しています。
+ボタンが押された場合は、次章の項目追加処理(addItem)が呼ばれます。

スポンサーリンク

項目追加処理

addItem()ファンクションで+ボタンを押された時に呼ばれる項目追加処理を行っています。

新規レコードの作成

ItemクラスのインスタンスであるnewItemを生成し、属性timestampに現在時刻(Date())を設定しています。
Itemクラスのイニシャライザには、引数としてデータベースを操作するManagedObjectContextを渡す必要があります。

データベースの保存

ManagedObjectContextのsave()メソッドで、データベースを保存(コミット)します。
このメソッドはエラーを返す可能性がある為、tryを使ったエラーキャッチが必要です。

アニメーションの指定

新規レコード追加表示時にアニメーションを適用しています。
@FetchRequestで取得したデータ群に対して、既にデフォルトのアニメーションタイプが指定されているので、この記述は蛇足のように思います。

スポンサーリンク

項目削除処理

行の削除が要求された場合は、deleteItems()ファンクションが呼ばれます。

レコードの削除

記述が複雑で、ぱっと見わかりずいらいですが、同様の処理は次のように書き直せます。

offsetsには削除対象の要素番号のコレクションが渡ってきますので、各要素番号に対応したエンティティをループで回して削除します。
削除には対象のエンティティを引数に、ManagedObjectContextのdelete()メソッドを呼び出します。

項目追加処理と同様に、データベースを保存(コミット)が必要です。

スポンサーリンク

アプリ起動時の処理

新規プロジェクト作成時に生成される「プロジェクト名.swift」ファイル内に、アプリ起動時の処理が記述されています。

永続コンテナのコントローラー生成

Core Dataに必要なオブジェクトの作成と管理を行う永続コンテナ(PersistentContainer)のコントローラーを生成します。
コントローラーの詳細については後述します。

ManagedObjectContextを環境変数に追加

データベース操作に使うManagedObjectContextを環境変数managedObjectContextに設定し、アプリケーションの各Viewで使用可能にします。

スポンサーリンク

永続コンテナコントローラー(PersistenceController)

Core Dataに必要なオブジェクトの作成と管理を行う永続コンテナ(PersistentContainer)のコントローラーで、新規プロジェクト作成時にUse Core Dataチェックを入れると生成されるPersistent.swiftファイルに定義されています。

インスタンスの取得方法には次の2通りあります。

PersistenceController.shared
通常版の永続コンテナコントローラーを返します。

PersistenceController.preview
preview用の永続コンテナコントローラーを返します。
通常版との違いは次の2点です。

  • preview用に初期データが設定される
  • DBが実ファイルでなくメモリ上に構築される(コミットしても永続化されない)
スポンサーリンク

プレビュー(preview)処理

ContentViewを表示するには、環境変数managedObjectContextが設定されている必要がある為、.environmentモディファイアを使って設定しています。
このとき使用しているPersistenceController.previewではプレビュー用のDB初期値が設定されます。

DB初期値は、Persistent.swiftの次の箇所で設定されていますので、ここを書き換えるとプレビュー時の初期値を変更可能です。

スポンサーリンク

合わせて読みたい記事

【SwiftUI】Core Dataの使い方:エンティエィ(Entity)を定義する
(2021/04/26 更新)Xcodeでエンティティを定義する方法を解説します。
【SwiftUI】Core Dataの使い方:準備編
SwiftUIでCore Dataを扱うための前提知識と、新規プロジェクトの作成方法について解説します。
【SwiftUI】Core Dataの使い方:基本編
SwiftUIでCore Dataの基本的な使い方を簡単なTodoリストアプリを例に解説します。
【SwiftUI】Core Dataの使い方:検索編(1/3)
データベースを検索して、オブジェクトとして取得するfetch処理について解説します。を先に見ておくことをおすすめします。
【SwiftUI】Core Dataの使い方:検索編(2/3)
検索条件を動的に変更する方法を解説します。の続編です。
【SwiftUI】Core Dataの使い方:検索編(3/3)
前の2つの記事では、SwiftUIの特徴であるデータバインディングの仕組みを使い、検索結果とViewを紐付ける方法を紹介しました。これにより、検索結果に応じてViewが自動で再描画されます。しかし、検索結果を別の処理のインプットに...
【SwiftUI】Core Dataの使い方:リレーションシップ編
リレーションシップを使ってエンティティ同士をリンクする方法を解説します。
スポンサーリンク
SwiftUI
カピ通信