【Swift/Core Data】NSManagedObjectのインスタンス作成方法!違いと使い方

この記事からわかること

  • SwiftCore Data利用する方法
  • エンティティ(NSManagedObject)インスタンス生成方法
  • Class DefinitionManual/NoneCategory/Extension違い
  • NSEntityDescription使い方

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

公式リファレンス:Core Data

環境

エンティティクラスが自動で生成される

参考文献:公式リファレンス:Generating Code

Core Dataでは.xcdatamodeldファイルで新しくエンティティを定義すると自動NSManagedObjectを継承したエンティティクラスファイルとプロパティファイルが生成されます。

【Swift UI】Core Dataの使い方!SQLiteにデータを永続的に保存する

生成されたファイル名はエンティティ名+CoreDataClass.swift形式とエンティティ名+CoreDataProperties.swift形式になるようです。

Person+CoreDataClass.swift

エンティティクラスファイルではCore Dataの管理対象オブジェクトであることを示すNSManagedObjectを継承しています。

@objc(Person)
public class Person: NSManagedObject {

}

Person+CoreDataProperties.swift

プロパティファイルではエンティティクラスを拡張してそのクラスのデータを取得するためNSFetchRequestを生成するメソッドや定義したプロパティが定義されています。

extension Person {

    @nonobjc  public class func fetchRequest() -> NSFetchRequest<Person> {
        return NSFetchRequest<Person>(entityName: "Person")
    }

    @NSManaged  public var age: Int16
    @NSManaged  public var id: UUID?
    @NSManaged  public var name: String?

}

extension Person : Identifiable {

}

これら2つのファイルが自動生成されるのは.xcdatamodeldファイルでエンティティをアクティブにした状態でインスペクタエリアに表示されるCodegen部分から設定を変更できます。初期値は自動生成されるClass Definitionになっており、Manual/NoneCategory/Extensionの3つから選択することが可能です。

【Swift/Core Data】NSManagedObjectのインスタンス作成方法!違いと使い方

Class Definition

Class Definitionエ2つのファイルを自動生成してくれる設定です。エンティティを登録後、最初にビルドされたタイミングで内部的に生成してくれます。

内部的に生成されるだけなので右側のファイルが表示されるナビゲータエリアには表示されません。実装する際にCannot find 'エンティティクラス' in scopeと出る場合は一度ビルドすれば解決するはずです。

定義ファイル自体を変更するたびに新しい内容のファイルに自動で更新されていくようです。

また自動生成されたクラスは編集することができないので処理を追加したい場合はManual/NoneまたはCategory/Extensionを選択する必要があります。

Category/Extension

Category/Extensionプロパティファイルの自動生成はそのままにエンティティクラスファイルのみ手動で作成する設定です。生成するにはXcodeの上部メニュー「Editor」>「Create NSManagedObject Subclass.」をクリックし、生成したいエンティティを選択するだけです。

クラスファイルとプロパティファイルがナビゲータエリアに表示されるようになります。この方法で表示されているファイルは編集可能になっているので任意の処理を追加することが可能になります。

【Swift/Core Data】NSManagedObjectのインスタンス作成方法!違いと使い方

Category/Extensionではプロパティファイルは自動生成されるのでナビゲータエリアに表示されているプロパティファイルと重複してしまうので明示的に削除しておく必要があります。

Manual/None

Manual/None自動生成をせずに2つのファイルとも手動で作成する設定です。手動で生成する手順はCategory/Extensionと同じくXcodeの上部メニュー「Editor」>「Create NSManagedObject Subclass.」をクリックし、生成したいエンティティを選択するだけです。

こちらは2つとも自動生成されないので削除する必要はありません。

エンティティクラスのインスタンス生成時のエラー

Core Dataで.xcdatamodeldファイルでエンティティを定義した後に、実際にデータを操作するためにインスタンス化しようとした際にそのままインスタンス化しようとするとエラーが出力されます。インスタンス化しただけではアプリはクラッシュしませんが、データベースに追加などを行うとアプリがクラッシュします。

let person = Person()
// CoreData: error: Failed to call designated initializer on NSManagedObject class 'Person' 

インスタンス化する方法

エンティティクラスをインスタンス化する方法はいくつか存在するので違いと方法を紹介していきます。

init(context moc: NSManagedObjectContext)

公式リファレンス:init(context moc: NSManagedObjectContext)

1つ目はNSManagedObjectのイニシャライザinit(context moc: NSManagedObjectContext)を使用する方法です。引数contextにはNSManagedObjectContextを渡します。

 let person = Person(context: context)

init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)

公式リファレンス:init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)

NSManagedObjectの別のイニシャライザinit(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)を使用する場合はNSEntityDescriptionを引数に渡す必要があります。

let entityDescription = NSEntityDescription.entity(forEntityName: String(describing: Person.self), in: context)!
let person = Person(entity: entityDescription, insertInto: nil)

引数insertIntoNSManagedObjectContextを渡すとデータベースに即座にデータを追加することができます。

NSEntityDescription.insertNewObject

公式リファレンス:NSEntityDescription.insertNewObject

class func insertNewObject(
    forEntityName entityName: String,
    into context: NSManagedObjectContext
) -> NSManagedObject

NSEntityDescriptioninsertNewObjectメソッドを使用してもインスタンスを生成することが可能です。ここで生成されるのはNSManagedObject型なので任意のクラスにするためにはキャストする必要があります。

let entity = NSEntityDescription.insertNewObject(forEntityName: String(describing: Person.self), into: context)
let person = entity as! Person

ジェネリクスを使用して汎用性の高いインスタンスメソッドを実装する

エンティティは複数定義することも多いので使いまわしやすいようにジェネリクスを使用して以下のように実装することでエンティティクラスが増えてもコードを回収することなく利用することができます。

おすすめ記事:【Swift】ジェネリクスの意味と使い方!Comparableプロトコルとは?

/// 新規作成
static func newEntity<T: NSManagedObject>() -> T {
    let entity = NSEntityDescription.insertNewObject(forEntityName: String(describing: T.self), into: context)
    return entity as! T
}

インスタンス化する際は変数側に取得したいクラスの型を指定します。

let newPerson: Person = DataRepository.newEntity()
let newSchool: School = DataRepository.newEntity()

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index