【Swift】Core Dataの設定。エンティティを継承させて属性のメンテナンスをしやすくする。(Swift 2.1、XCode 7.2)
Entityの設定
Core Dataを使ってデータを外部ファイルに保存したり、外部ファイルからデータを読み込んだりするときに、モデルに定義しているEntity(以下、エンティティ)を用いて形式の変換が行われることについて前回記事で説明した。⇒「前回記事」
本記事では、そのエンティティのデータモデルインスペクタの設定について説明する。
動作確認は前回記事の続きから行う。前回記事終了時点のXcodeプロジェクトをGitHubに置いたので、試してみる人はご利用されたし。
⇒「テスト用プロジェクト」
テキストフィールドに入力した文字列をCore Dataを使って保存するだけの単純なプロジェクトである。
エンティティのデータモデルインスペクタの設定を開くには、下図赤枠の「プロジェクト名.xcdatamodeld」を選択、黄緑枠のPlayerを選択、紫枠のデータモデルインスペクタボタンを押すと設定画面が表示される。
設定項目の内容を1つずつ確認する。
Name
エンティティの名前。ソースコードからエンティティにアクセスするための識別子になる。
Abstract Entity
チェックを入れると抽象エンティティとなって、他のエンティティで継承できるようになる。
例えば、BaseballPlayerエンティティ、SoccerPlayerエンティティなど、人を表すエンティティをたくさん作るときに名前、年齢などのすべてのエンティティに共通して存在する属性を1つずつ追加していくと作業が煩雑になり、あとから修正もしにくい。
そんなときは、すべてのエンティティに共通して存在する属性をPlayerエンティティに集めて抽象エンティティにし、Playerエンティティを継承させたBaseballPlayerエンティティ、SoccerPlayerエンティティを作る。
実際に作ってみよう。
下図赤枠のPlayerを選択、黄緑枠のデータモデルインスペクタボタンを押して設定画面を表示し、Abstract Entityにチェックを入れる。これでPlayerエンティティが抽象エンティティになった。
下図黄緑枠のAdd Entityボタンを押すと紫枠に新しいエンティティが追加される。紫枠のエンティティを選択、赤枠のデータモデルインスペクタボタンを押して設定画面を表示する。
Nameに「BaseballPlayer」、Parent Entityに「Player」を設定する。これでPlayerエンティティの属性がBaseballPlayerエンティティで使えるようになった。
ViewController.swiftを以下のコードに変更する。変更点は「Player」を「BaseballPlayer」に変えただけ。
このコードでPlayerエンティティから継承したBaseballPlayerのnameエンティティが問題なく利用できることを確認する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
// // ViewController.swift // import UIKit import CoreData class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var testLabel: UILabel! @IBOutlet weak var testTextField: UITextField! //管理オブジェクトコンテキスト var managedContext:NSManagedObjectContext! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() do { //管理オブジェクトコンテキストを取得する。 let applicationDelegate = UIApplication.sharedApplication().delegate as! AppDelegate managedContext = applicationDelegate.managedObjectContext //管理オブジェクトコンテキストからPlayerエンティティを取得する。 let fetchRequest = NSFetchRequest(entityName: "BaseballPlayer") let result = try managedContext.executeFetchRequest(fetchRequest) as! [NSManagedObject] //すべてのPlayerエンティティの名前をラベルに表示する。 for data in result { testLabel.text = testLabel.text! + "," + String(data.valueForKey("name")!) } //デリゲート先に自分を設定する。 testTextField.delegate = self } catch { print(error) } } //Returnキー押下時の呼び出しメソッド func textFieldShouldReturn(textField:UITextField) -> Bool { do { //ラベルの値にテキストフィールドの値を追記する。 testLabel.text = testLabel.text! + "," + testTextField.text! //新しいPlayerエンティティを管理オブジェクトコンテキストに格納する。 let player = NSEntityDescription.insertNewObjectForEntityForName("BaseballPlayer", inManagedObjectContext: managedContext) //Playerエンティティの名前にテキストフィールドの値を設定する。 player.setValue(testTextField.text, forKey:"name") //管理オブジェクトコンテキストの中身を永続化する。 try managedContext.save() //キーボードをしまう self.view.endEditing(true) } catch { print(error) } return true } } |
以下は実際のプレイ動画。問題なくname属性を使うことができた。
アプリを起動すると以下ようなエラーが発生することがある。モデルと保存データが不一致のために起きたエラーだ。
アプリでデータを保存したあとにモデルを変更してアプリを再起動すると起きる。マイグレーションすればエラーは解消されるが、手っ取り早く解消するなら、アプリを削除してシミュレータを起動しなおすのが良い。
ちなみにアプリを削除する方法は、以下の動画のようにアイコンを長押しして×ボタン。
Parent Entity
Entityを継承させる場合に抽象エンティティ名を設定する。
先ほどの例でBaseballPlayerエンティティを作ったときにParent Entityに「Player」を設定した。
設定項目の確認は次回記事に続く。。