【Swift】Core Dataの設定。エンティティの属性の型、範囲、初期値を設定する。(Swift 2.1、XCode 7.2)
Attributeの設定
本記事は、前回記事「Attributeの設定」の続きである。⇒「前回記事」
Optional
必須項目、任意項目のどちらにするかの設定。チェックを入れると任意項目になり、値を設定しなくてもエラーは発生しない。デフォルトはチェックが入っている。
チェックを外して必須項目にした場合は、値を設定しないとデータを保存する段階で以下のエラー(Code=1570)が発生する。
indexed
チェックを入れると、この属性のインデックスが生成される。インデックスについては次の記事も参照されたし。⇒「インデックスとは」
Attribute Type
属性の型を指定する。型によってValidationに設定できる項目が変わる。
下表は設定可能な型の一覧。
設定名 | 設定値 | Validation | |
---|---|---|---|
1 | Undefined | 未設定 | 無し |
2 | Integer 16 | 整数(-3万から3万) -32768 ~ 32767 | 範囲、初期値 |
3 | Integer 32 | 整数(-21億から21億) -2147483648 ~ 2147483647 | 範囲、初期値 |
4 | Integer 64 | 整数(-922京から922京) –9223372036854775808 ~ 9223372036854775807 | 範囲、初期値 |
5 | Decimal | 10進型 | 範囲、初期値 |
6 | Double | 不動小数点(有効桁数は約15桁) | 範囲、初期値 |
7 | Float | 不動小数点(有効桁数は約7桁) | 範囲、初期値 |
8 | String | 文字列 | 文字列長、初期値、正規表現 |
9 | Boolean | 真理値(trueまたはfalse) | 初期値 |
10 | Date | 日付 | 日付範囲、初期日付 |
11 | Binary Data | バイナリデータ | |
12 | Transformable | NSData型に変換可能なオブジェクト |
上記表のValidationについて説明する。
動作確認をするのに使ったXCodeのプロジェクトをGitHubに置いたので試してみる人はご利用されたし。
⇒「テスト用プロジェクト」
使い方は、ピッカーで保存する型を選択し、テキストフィールドに値を入力する。「保存」ボタンを押すとCore Dataを使ってデータが保存され、「読込」ボタンを押すと保存したデータがデバッグエリアに表示される。
以下はViewController.swiftのソースコード。動作確認用なので処理効率やエラーハンドリングについては考慮していない。
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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
// // ViewController.swift // import UIKit import CoreData class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var testLabel: UILabel! @IBOutlet weak var testTextField1: UITextField! let dataList = ["Integer 16","Integer 32","Integer 64","Decimal","Double","Float","String","Boolean","Date", "Binary Data", "Transformable"] var selectStr:String = "Integer 16" //管理オブジェクトコンテキスト var managedContext:NSManagedObjectContext! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //管理オブジェクトコンテキストを取得する。 let applicationDelegate = UIApplication.sharedApplication().delegate as! AppDelegate managedContext = applicationDelegate.managedObjectContext //デリゲート先に自分を設定する。 testTextField1.delegate = self } //コンポーネントの個数を返すメソッド func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { return 1 } //コンポーネントに含まれるデータの個数を返すメソッド func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return dataList.count } //データを返すメソッド func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return dataList[row] } //データ選択時の呼び出しメソッド func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { //選択されたデータを取得する。 selectStr = self.pickerView(pickerView, titleForRow: pickerView.selectedRowInComponent(0), forComponent: 0)! } //Returnキー押下時の呼び出しメソッド func textFieldShouldReturn(textField:UITextField) -> Bool { //キーボードをしまう self.view.endEditing(true) return true } //保存ボタン押下時の呼び出しメソッド @IBAction func pushButton(sender: UIButton) { do { //新しいオブジェクトを管理オブジェクトコンテキストに格納する。 let player = NSEntityDescription.insertNewObjectForEntityForName("Player", inManagedObjectContext: managedContext) as! Player //ピッカーの値をもとに保存先の属性を変更する。 switch selectStr { case "Integer 16": player.testInteger16 = Int(testTextField1.text!) case "Integer 32": player.testInteger32 = Int(testTextField1.text!) case "Integer 64": player.testInteger64 = Int(testTextField1.text!) case "Decimal": player.testDecimal = NSDecimalNumber(double: Double(testTextField1.text!)!) case "Double": player.testDouble = Double(testTextField1.text!) case "Float": player.testFloat = Float(testTextField1.text!) case "String": player.testString = String(testTextField1.text!) case "Boolean": player.testBoolean = NSString(string:testTextField1.text!).boolValue case "Date": let formatter = NSDateFormatter() formatter.locale = NSLocale(localeIdentifier: "ja") formatter.dateFormat = "yyyy/MM/dd HH:mm:ss" player.testDate = formatter.dateFromString(String(testTextField1.text!)) case "Binary": let data = NSData(data: String(testTextField1.text!).dataUsingEncoding(NSUTF8StringEncoding)!) player.testBinaryData = data case "Transformable": let data = TestObject() data.message = String(testTextField1.text!) player.testTransformable = data default: print("想定外") } //管理オブジェクトコンテキストに格納したデータを保存する。 try managedContext.save() } catch { print(error) } } //読込ボタン押下時の呼び出しメソッド @IBAction func readData(sender: UIButton) { do { //保存データを取得する。 let fetchRequest = NSFetchRequest(entityName: "Player") let result = try managedContext.executeFetchRequest(fetchRequest) as! [Player] //取得結果を出力する。 let data = result.last! print("testInteger16=\(data.testInteger16!)") print("testInteger32=\(data.testInteger32!)") print("testInteger64=\(data.testInteger64!)") print("testDecimal=\(data.testDecimal!)") print("testDouble=\(data.testDouble!)") print("testFloat=\(data.testFloat!)") if let test = data.testString { print("testString=\(test)") } if let test = data.testBoolean { print("testBoolean=\(test)") } if let test = data.testDate { print("testDate=\(test)") } if let test = data.testBinaryData { print("testBinaryData=\(test)") } if let test = data.testTransformable as? TestObject { print("testTransformable=\(test.message)") } print("") } catch { print(error) } } } //Transformableテスト用 class TestObject: NSObject, NSCoding { var message:String! override init() { super.init() } //デコード required init?(coder aDecoder: NSCoder) { message = aDecoder.decodeObjectForKey("message")! as! String } //エンコード func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(message, forKey: "message") } } |
範囲(Minimum, Maximum)
設定できる値の範囲を指定する。
例えば、下図赤枠のように型がInteger 16の属性に、最小値に100、最大値200のValidationを設定し、300を保存しようとするとエラーが発生して保存に失敗する。
以下はエラーメッセージ
初期値(Default)
オブジェクト生成時の属性の初期値を指定する。
文字列長(MinLength, MaxLength)
属性に設定できる文字列の文字数の範囲を指定する。
正規表現(Reg. Ex.)
属性に設定できる文字列の正規表現を指定する。例えば、先頭に「TEST」がついている文字列のみ設定できるようにしたい場合は「TEST.*」になる。
日付範囲(Minimum Value, Maximum Date)
属性に設定できる日付の範囲を年月日時分秒で指定する。なぜか最小の項目名が「Value」、最大の項目名が「Date」になっている。修正される前に記念スクショを撮っておこう。
その他の留意事項について以下に説明する。
Decimalについて
Decimalを簡単に言うと、大きな桁数を符合付きで正確に保存できる型である。DoubleやFloatの不動小数点型の場合、無限小数による丸め誤差が発生することがあるが、Decimalを使うとその心配はなく正確な数値を得ることができる。
イメージしづらいので計算して確かめよう。10進数の小数部を2進数に変換する方法は、数字を2倍した値が1未満なら0をメモする。1以上なら1をメモして1を引く。これを繰り返して0になった時点で終了。
例えば、10進数の0.1を2進数に変換すると以下の計算になる。
0.1 × 2倍 = 0.2 ⇒ 0
0.2 × 2倍 = 0.4 ⇒ 0
0.4 × 2倍 = 0.8 ⇒ 0
0.8 × 2倍 = 1.6 ⇒ 1
0.6 × 2倍 = 1.2 ⇒ 1
0.2 × 2倍 = 0.4 ⇒ 0
…(無限)
メモした値を並べたものが2進数に変換した値になる。
0.0001100110011001100110011…無限
そして、2進数に変換した値を10進数に戻すと10進数も無限小数になり、ぴったり0.1にはならない。これがDoubleやFloatが正確にならないイメージである。
一方、Decimal型は整数値、符合、小数位置を持って保存されているので正確な値で比較、計算することができる。ただし、DoubleやFloatを使うよりパフォーマンスが劣るので必要なものに絞って利用したほうが良い。
Binary Data
NSData型のデータを設定する。画像などのサイズが大きいデータが保存されることが想定される。
この型を選択するとOptionに「Allows External Storage」の設定項目が現れる。チェックを入れれば、データを外部ストレージに保存することを許可することになる。
Transformable
NSCordingプロトコルを適用しているクラスのインスタンスをNsData型に変換して保存してくれる。独自の変換処理を行いたい場合は、NSValueTransformaerクラスのサブクラスをNameに設定する。
Advanced(高度な設定)
高度な設定に「index in Spotlight」と「Store in External Record File」があるが、OS X用の設定なので検証対象外とする。