100DaysOfSwiftUI Day61のChallengeをやってみる(CoreData対応)

なんとなくDay61を見てみたら、CoreData対応でした。

ちょうど、CoreData対応と非対応のプロジェクトの設定を見比べたところだったので、続けてやっていこうかと

非CoreData設定のプロジェクトを、CoreData対応する方法

変更するファイルは、2つです。

AppDelegate.swift
以下のコードを追加することで、NSPersistentContainerを使えるようになります。
SceneDelegate.swift
ContentViewが生成される前に、environmentObjectとして、ManagedObjectContextを設定しておくコードです。
“DataModel”ファイル
新規ファイルとして、”Data Model”ファイルを追加します。

これで、CoreDataを使うをチェックして作ったプロジェクトと同様の状態になります。
クラスとしては、手で作ったクラスと同等の、UserList, User, Friend, Tagを作りました。

JSON経由で読み込んだオブジェクトの、NSManagedObjectへの変換

当初は、自分でClassを作っていましたが、同様のモデルをCoreData上に作ります。

SwiftUIで使うことになると思うので、コード生成したUserListに以下の追加を行います。

CoreDataの中では、To Manyな関係は、NSSetで表現されているので、そのままでは、SwiftUIの中でパースするのが難しくなります。
このコードを追加しておくことで、List等で使いやすくなります。

Encode/Decodeが難関

NSManagedObjectを継承したクラスを、Codableにする必要があります。文字で書くと簡単ですが、難しかったです。

NSManagedObjectを継承したクラスのinitializerには、context等が必要となります。CodableをConformする時に必要となるinitializerは、”required init(from decoder: Decoder) throws”であり、contextを引数として渡す余地がありません。

Googleし続けた結果、どうやら、decoderには、userInfoというDictionaryを付与できるので、そこにcontextを渡すことができました。

渡す方(UserListを生成した後この関数を呼んでWebから読み込ませてます)

受け取る方(UserListのDecodable対応のためのinit)

NSManagedObjectを継承したクラスのDecodable対応

どうやってDecodeするかは、JSONや構造依存ですが、initializerを定義することで、Decodableにできます。
関係のあるクラスは、数珠つなぎに呼ばれると思いますので、関係するクラスすべてをDecodable対応する必要があります。

Decodable(/Encodable)とCoreData(NSManagedObjectを継承したクラス)を混ぜることがきました

結構長くなっていますが、上記のような形で、CoreDataで管理されながらCodableにConformすることができました。

  • DecoderのuserInfo経由で、NSManagedObjectContextを受け渡す
  • Codableにするためには、NSManagedObjectを継承するクラスをコード生成しないとできない
便利プロパティその1
CoreDataでは、すべてOptionalに定義されています。SwiftUIと組み合わせて使おうとすると、常にOptionalを外す作業が必要となります。それを避けるために、以下のようなプロパティを作っておくと、非常に作業が捗りますし、コードが読みやすくなるかと思います。

便利プロパティその2
To Multiなrelationを作成すると上記のようなコードが生成されるのですが、SwiftUIと接続を予定している場合には、下記のようなSwiftUIからアクセスしやすくなるようなプロパティを作っておくと非常に便利です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です