【Swift】Core Dataの設定。外部ファイルに保存されない一時的な属性を定義する。(Swift 2.1、XCode 7.2)
Attributeの設定
本記事ではCore Dataのエンティティに定義されているAttribute(以下、属性)の設定について説明する。
以降の検証を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる人はご利用されたし。
⇒「テスト用プロジェクト」
事前準備では、氏名と年齢を入力して登録ボタンを押すとCore Dataを使って外部ファイルにデータが保存されるものを実装しておいた。
属性の設定画面を開くには、下図赤枠の「プロジェクト名.xcdatamodeld」を選択、黄緑枠のエンティティを選択、黄枠の属性を選択、紫枠のデータモデルインスペクタボタンを押す。
Name
属性の名前。
Transient
チェックを入れると、外部ファイルに保存されない一時的な属性になる。
試してみよう。下図赤枠の「+」ボタンを押して属性を追加する。黄緑枠のデータモデルインスペクタボタンを押して設定画面を表示し、Nameに「Test」を入力、Transientにチェックを入れる。
下図赤枠の「プロジェクト名.xcdatamodeld」を選択したあと、メニュー⇒「Editor」⇒「Create NSManagedObject Subclass」とたどる。
データモデルの一覧が表示されるので、「プロジェクト名」にチェックが入っていることを確認して「Next」ボタンを押す。
データモデルに定義されているEntityの一覧が表示されるので、Playerにチェックを入れて「Next」ボタンを押す。
保存先を指定する画面が表示されるので、プロジェクトのフォルダが指定されていることを確認して「Create」ボタンを押す。
すると、Player+CoreDataProperties.swiftのPlayerクラスにtestプロパティが追加される。通常の属性と一時的な属性の宣言は同じである。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// // Player+CoreDataProperties.swift // import Foundation import CoreData extension Player { @NSManaged var age: NSNumber? @NSManaged var name: String? @NSManaged var test: NSNumber? } |
ViewController.swiftを以下のコードに変更する(青色網掛けが変更箇所)。
管理オブジェクトコンテキストに新しいオブジェクトを追加するときにtestプロパティに777を設定したのと、ラベルにtestプロパティの値も表示するようにした。
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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
// // ViewController.swift // import UIKit import CoreData class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var testLabel: UILabel! @IBOutlet weak var testTextField1: UITextField! @IBOutlet weak var testTextField2: UITextField! //管理オブジェクトコンテキスト var managedContext:NSManagedObjectContext! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //管理オブジェクトコンテキストを取得する。 let applicationDelegate = UIApplication.sharedApplication().delegate as! AppDelegate managedContext = applicationDelegate.managedObjectContext //managedContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy //保存データを表示する。 displayData() //デリゲート先に自分を設定する。 testTextField1.delegate = self testTextField2.delegate = self } //保存データ表示メソッド func displayData(){ do { //Playエンティティで保存されているデータを取得する。 let fetchRequest = NSFetchRequest(entityName: "Player") let result = try managedContext.executeFetchRequest(fetchRequest) as! [Player] //取得したデータをラベルに表示する。 var outputStr = "" for data in result { if let name = data.name, age = data.age { outputStr = outputStr + "," + name + "," + String(age) + "," + String(data.test!) //◀︎変更箇所 } } testLabel.text = outputStr } catch { print(error) } } //Returnキー押下時の呼び出しメソッド func textFieldShouldReturn(textField:UITextField) -> Bool { //キーボードをしまう self.view.endEditing(true) return true } //ボタン押下時の呼び出しメソッド @IBAction func pushButton(sender: UIButton) { do { //nameの値が同じオブジェクトを検索する。 let fetchRequest = NSFetchRequest(entityName: "Player") fetchRequest.predicate = NSPredicate(format: "name = %@", testTextField1.text!) let players = try managedContext.executeFetchRequest(fetchRequest) as! [Player] if (players.count == 0) { //検索にヒットしなかった場合は新しいオブジェクトを管理オブジェクトコンテキストに格納する。 let player = NSEntityDescription.insertNewObjectForEntityForName("Player", inManagedObjectContext: managedContext) as! Player player.name = testTextField1.text! player.age = Int(testTextField2.text!) player.test = 777 //◀︎追加箇所 } else if(players.count == 1) { //検索にヒットした場合は、そのオブジェクトを更新する。 players.first!.age = Int(testTextField2.text!) } else { print("想定外") } //管理オブジェクトコンテキストに格納したデータを保存する。 try managedContext.save() //データを表示する。 displayData() } catch { print(error) } } } |
以下は実際のプレイ動画。777に設定したtestプロパティの値が保存されずに0になることが分かる。
testプロパティの値が消えるイメージを下図で説明する。
管理オブジェクトコンテキストに「name=太郎、age=20歳、test=777」のオブジェクトを追加する。この段階ではtestプロパティは777のままである。
次に、管理オブジェクトコンテキストのsaveメソッドを呼び出すと、オブジェクトが外部ファイルに保存されるが、testプロパティは一時的な属性のため値は保存されずにname、ageの値が保存される。保存したオブジェクトは管理オブジェクトコンテキストの管理対象から外れて消滅する。
そのため、同じオブジェクトを読み込むときは外部ファイルから読み込まれてtestプロパティは初期値になっている。
ただし、saveメソッドの処理が終わった直後にオブジェクトが消滅するのではなく、saveメソッドを含むプロセスが終了した段階に消滅するような検証結果になっている。プレイ動画でも最初は777が表示されたのもそのためと考えられる。これについては明確になり次第追記する。
では、saveメソッドを呼び出さなかったらtestプロパティの値はずっと777のままなのかを確認しておこう。
ViewController.swiftの以下のコードをコメントアウトしてシミュレーターを起動する。
1 2 3 |
//管理オブジェクトコンテキストに格納したデータを保存する。 //try managedContext.save() |
以下は実際のプレイ動画。testプロパティの値はずっと777になった。
ただし、アプリを終了するときに自動でsaveメソッドが呼び出されるようになっているので、アプリを再起動するとtestプロパティが初期値0のデータが表示される(AppDelegate.swiftを参照)。