見出し画像

【徒然DB】気ままにUIKit-CoreData編4〜 Indexes,Constraints,UserInfo〜

概要

このマガジンは四十を過ぎたおっさんが、

を参考にStoryboardでiOSアプリを完全に趣味で楽しんでいるだけな記事を気ままに上げてます。

今回

をハイ、レッツゴ🕺

前準備

念の為、

  1. バックアップ

  2. 新規クラスを追加

  3. メニュービューと新規ビューを追加

  4. 今回用の事前準備

をやってから本題へ💃

前回の続きってことなんでこんな感じで〜〜〜

本題

ここら辺の今回は説明の様子👀

Indexes:見ての通り既に存在してないので参考までに〜〜〜

インデックスを作る属性を指定する。インデックスとは、データ検索を高速化するための索引

👉インデックスには単一インデックスと複合インデックスがあるが、Indexesの設定項目は、主に複合インデックスを定義するのに使われる。
単一インデックスは属性ごとの設定画面からも設定できる。

単一インデックスとは、1つの属性をキーにしてデータを検索するときに使われるインデックスである。
例えば「name=’佐藤’」で検索するときは、属性nameのみ使われるので単一インデックスである。

複合インデックスとは、2つ以上の属性をキーにしてデータを検索するときに使われるインデックスである。
例えば「name=’佐藤’ かつ age=20」で検索するときは、属性nameとageが使われるので複合インデックスである。

・メリット:インデックスはデータ検索を高速化させる

・デメリット:データが追加されるたびにインデックスの更新が実施されるので、データ追加が頻繁に行われるエンティティにインデックスをたくさん定義すると、データ追加時の処理時間が長くなってしまうので注意されたし。

てことらしい👀
長いね💦SQLとかでは、Idxなんかの形でインデックスをやるけど、CoreDataでは消えたのかな💦

他のメニューにも見当たらないね💦

Constraints

ここに追加した属性はデータが重複できなくなる(一意制約)。

例えば、nameが「佐藤」のデータ2つを保存しようとすると、2つ目のデータを保存するタイミングでConflict(衝突)のエラーが発生する。

+ボタンをクリック〜〜〜
なんか追加されたので〜〜〜
nameに変更して〜〜〜
//
//  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: "Player")
            let result = try managedContext.executeFetchRequest(fetchRequest) as! [Player]
            //すべてのPlayerエンティティの名前をラベルに表示する。
            for data in result {
                testLabel.text = testLabel.text! + "," + data.name!
            }
            //デリゲート先に自分を設定する。
            testTextField.delegate = self
        } catch {
            //エラーメッセージをアラートで表示する。
            let alert = UIAlertController(title:"エラー", message:String(error), preferredStyle:UIAlertControllerStyle.Alert)
            self.presentViewController(alert, animated:true, completion:nil)
        }
    }
    //Returnキー押下時の呼び出しメソッド
    func textFieldShouldReturn(textField:UITextField) -> Bool {
        do {
            //ラベルの値にテキストフィールドの値を追記する。
            testLabel.text = testLabel.text! + "," + testTextField.text!
            //新しいPlayerエンティティを管理オブジェクトコンテキストに格納する。
            let player = NSEntityDescription.insertNewObjectForEntityForName("Player", inManagedObjectContext: managedContext) as! Player
            //Playerエンティティの名前にテキストフィールドの値を設定する。
            player.name = testTextField.text
            //管理オブジェクトコンテキストの中身を永続化する。
            try managedContext.save()
            //キーボードをしまう            
            self.view.endEditing(true)
        } catch {
            //エラーメッセージをアラートで表示する。
            let alert = UIAlertController(title:"エラー", message:String(error), preferredStyle:UIAlertControllerStyle.Alert)
            self.presentViewController(alert, animated:true, completion:nil)
        }
        return true
    }
}

を参考に〜〜〜

今回のコード(Constraints)

class IndexesCoreDataViewController: UIViewController, UITextFieldDelegate{

    @IBOutlet weak var myTextField: UITextField!
    @IBOutlet weak var myLabel: UILabel!
    //管理オブジェクトコンテキスト
    var managedContext:NSManagedObjectContext!
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        do {
            //管理オブジェクトコンテキストを取得する。
            let applicationDelegate = UIApplication.shared.delegate as! AppDelegate
            managedContext = applicationDelegate.persistentContainer.viewContext
            //管理オブジェクトコンテキストからPlayerエンティティを取得する。
            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Player")
            let result = try managedContext.fetch(fetchRequest) as! [Player]
            //すべてのPlayerエンティティの名前をラベルに表示する。
            for data in result {
                myLabel.text = myLabel.text! + "," + data.name!
            }
            //デリゲート先に自分を設定する。
            myTextField.delegate = self
        } catch {
            //エラーメッセージをアラートで表示する。
            let alert = UIAlertController(
                title: "エラー",
                message: String(describing: error),
                preferredStyle: UIAlertController.Style.alert
            )
            self.present(alert, animated:true, completion:nil)
        }
    }
    //Returnキー押下時の呼び出しメソッド
    func textFieldShouldReturn(_ textField:UITextField) -> Bool {
        do {
            //ラベルの値にテキストフィールドの値を追記する。
            myLabel.text = myLabel.text! + "," + myTextField.text!
            //新しいPlayerエンティティを管理オブジェクトコンテキストに格納する。
            let player = NSEntityDescription.insertNewObject(forEntityName: "Player", into: managedContext) as! Player
            //Playerエンティティの名前にテキストフィールドの値を設定する。
            player.name = myTextField.text
            //管理オブジェクトコンテキストの中身を永続化する。
            try managedContext.save()
            //キーボードをしまう
            self.view.endEditing(true)
        } catch {
            //エラーメッセージをアラートで表示する。
            let alert = UIAlertController(
                title: "エラー",
                message: String(describing: error),
                preferredStyle: UIAlertController.Style.alert
            )
            self.present(alert, animated:true, completion:nil)
        }
        return true
    }
}

オイラのプロジェクトでは既に、重複するnameデータが複数存在するので〜〜〜

実行前にエラーになっちゃうので〜〜〜、コードをあくまでも参考程度でお願いします🙇

今回のポイント

Constraintsに関しては、ACCESSなんかでも追加できなくはないんだけど、
よほど強固な設計をしっかりしてるデータベース以外、あんまり追加した経験はないなあ🤔
(例)このID列は1回、登録しちゃうと、重複を許さないので、制約追加
って感じでしか使わないかなあ🤔
IDや電話番号に関しては、重複するとおかしいけど、名前に関しては、同姓同名なんて山ほどいるから、nameに制約をつけてしまうと、同じ佐藤さんが登録できなくなってしまうしね💦

User Info

User Infoとは、項目につける付加情報

👉エンティティの設定の下にあるUser Infoは、選択しているエンティティにつける付加情報

コイツの〜〜
+ボタンをクリック〜〜〜

「Returnキー押下時の呼び出しメソッド」に以下のコードを追加

//ラベルにUser Infoの値を設定する。
testLabel.text = player.entity.userInfo!["testKey"] as? String

を参考に〜〜〜

//ラベルにUser Infoの値を設定する。
myLabel.text = player.entity.userInfo!["SportsKey"] as? String

てな感じで〜〜〜

変更は出来たんだけど、
果たしてこれをいつ使うんだろうって感じだね〜〜〜

今回のコード(まとめ:参考程度)

あくまでも、参考程度に〜〜〜

class IndexesCoreDataViewController: UIViewController, UITextFieldDelegate{

    @IBOutlet weak var myTextField: UITextField!
    @IBOutlet weak var myLabel: UILabel!
    //管理オブジェクトコンテキスト
    var managedContext:NSManagedObjectContext!
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        do {
            //管理オブジェクトコンテキストを取得する。
            let applicationDelegate = UIApplication.shared.delegate as! AppDelegate
            managedContext = applicationDelegate.persistentContainer.viewContext
            //管理オブジェクトコンテキストからPlayerエンティティを取得する。
            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Player")
            let result = try managedContext.fetch(fetchRequest) as! [Player]
            //すべてのPlayerエンティティの名前をラベルに表示する。
            for data in result {
                myLabel.text = myLabel.text! + "," + data.name!
            }
            //デリゲート先に自分を設定する。
            myTextField.delegate = self
        } catch {
            //エラーメッセージをアラートで表示する。
            let alert = UIAlertController(
                title: "エラー",
                message: String(describing: error),
                preferredStyle: UIAlertController.Style.alert
            )
            self.present(alert, animated:true, completion:nil)
        }
    }
    //Returnキー押下時の呼び出しメソッド
    func textFieldShouldReturn(_ textField:UITextField) -> Bool {
        do {
            //ラベルの値にテキストフィールドの値を追記する。
            myLabel.text = myLabel.text! + "," + myTextField.text!
            //新しいPlayerエンティティを管理オブジェクトコンテキストに格納する。
            let player = NSEntityDescription.insertNewObject(forEntityName: "Player", into: managedContext) as! Player
            //Playerエンティティの名前にテキストフィールドの値を設定する。
            player.name = myTextField.text
            //管理オブジェクトコンテキストの中身を永続化する。
            try managedContext.save()
            //キーボードをしまう
            self.view.endEditing(true)
            //ラベルにUser Infoの値を設定する。
            myLabel.text = player.entity.userInfo!["SportsKey"] as? String
        } catch {
            //エラーメッセージをアラートで表示する。
            let alert = UIAlertController(
                title: "エラー",
                message: String(describing: error),
                preferredStyle: UIAlertController.Style.alert
            )
            self.present(alert, animated:true, completion:nil)
        }
        return true
    }
}

ブラッシュアップ

使わないので、UserInfoも削除👀

ハイ、削除

地球儀ボタン追加

てな感じで〜〜〜

記事公開後、

ハイ、完了💃
実機も問題なし🕺

Apple公式

さてと、次回は、

をレッツゴする🕺

この記事が気に入ったらサポートをしてみませんか?