見出し画像

【徒然DB】気ままにUIKit-CoreData編1〜基本中の基本〜

概要

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

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

今回

をハイ、レッツゴする🕺

ここから先は、

実際の現場では、RealmやSQLite、その他のデータベースでやるかな

と思うので、あくまでも

番外編

以前の記事で書いてるとおり、

気ままに、今年中に、残りの記事を消化できればいいな

くらいなモノなので、参考にしたければ参考にしてね程度で記事にしてく〜〜〜

多分、おそらく全部は、正常に動かないだろうなと予想してまする🕺

CoreData周りだから、

データベースはRealmとか他のフレームワーク使ってるからいいや
とか、
データ管理のアプリなんて作らないからいらない

って人にはあまり参考にならないかも〜〜〜〜
ちなみにオイラも、

2Dゲームなんて今のところ作らないから、SpriteKit周りはやらないしね💦

こういう連載マガジンは必要そうなところから動かして、自分で作ってみて、、、

て感じでやってくのもひとつの方法
大系的にどんな機能があるかに触れたいとか理解したいって人は、全部触れた方がいいかなって思うけどね👀

前準備

念の為、

  1. バックアップ

をいつもどおりやってから本題へ💃

てな感じで💦

本題

Core Dataとは、

アプリで入力または編集したデータを外部ファイルに保存する機能

  • NSUserDefault:大量または複雑なデータを扱うのに適してない。

  • Core Data:大量または複雑なデータを扱うのに適したフレームワーク。

ってことみたいね👀

Core Dataを使ってみる

なんだけど、元々、組み込んでいってるプロジェクトは、最初の段階で

Use CoreDataにチェック

を入れて作り直しているので、既に

てな感じでデータモデルが初期設定で追加されてる👀

ポイント

CoreDataを後から追加すればいいで、Use CoreDataにチェックし忘れてる場合、

で、新たに追加できなくはないんだけど、

これまでの記事の機能を組み込んでいって、

ここまでビューが多くなってくると、

最初からやり直すことが中々、労力になるので、

後から機能追加でCoreDataを使うことも想定して、最初からチェックを入れておいた方がいいんだよね〜〜〜
実際、クライアントの要求なんていつ変わるかわからないし。

ま、SwiftUIでやる分には、ビュー自体は全てコードで作るからそこまで手間ではないんだけどね💦

⒈事前準備

CoreData用のメニュービューを増やして〜〜〜
今回用のビューを増やして、ラベルとテキストフィールドを追加〜〜〜
ビューに今回用の新規クラスを適用して〜〜〜
てな感じで、追加したパーツをアウトレット接続〜〜〜
//
//  ViewController.swift
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var testLabel: UILabel!
    @IBOutlet weak var testTextField: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        //デリゲート先に自分を設定する。
        testTextField.delegate = self
    }
    //Returnキー押下時の呼び出しメソッド
    func textFieldShouldReturn(textField:UITextField) -> Bool {
        //ラベルの値にテキストフィールドの値を追記する。
        testLabel.text = testLabel.text! + "," + testTextField.text!
        //キーボードをしまう
        self.view.endEditing(true)
        return true
    }
}

を参考に〜〜〜

てな感じでコードを追加して〜〜〜
class CoreDataStandardViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var myLabel: UILabel!
    @IBOutlet weak var myTextField: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        //デリゲート先に自分を設定する。
        myTextField.delegate = self
    }
    //Returnキー押下時の呼び出しメソッド
    func textFieldShouldReturn(_ textField:UITextField) -> Bool {
        //ラベルの値にテキストフィールドの値を追記する。
        myLabel.text = myLabel.text! + "," + myTextField.text!
        //キーボードをしまう
        self.view.endEditing(true)
        return true
    }
}
入力して〜〜〜表示されたところ〜〜〜
開き直すと、さっきのデータは消えてるね👀

⒉ここからの操作を間違うと面倒臭そうなので、一旦バックアップ

バックアップしたところ👀

こういうデカすぎるプロジェクトファイルでは未知の領域なんだけど、正常にできるか試す意味でもやってく〜〜〜🕺

⒊モデルにエンティティを追加

エンティティとは、
オブジェクトが持つプロパティや関係が記載されている定義書
👉管理オブジェクトコンテキストに格納するオブジェクト1つにつき1つのエンティティが割り当たる。

てことらしい👀

左下のAdd Entityをクリック〜〜〜
Entityが追加された🕺
いつものAttributeインスペクターでNameをPlayerに〜〜〜
続けてここの+ボタンを推してAttributeを追加しろってことみたいなんで〜〜〜
てな感じで追加〜〜〜

っと、大きくしとこう

てな感じね👀

⒋コード組み込み

//
//  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! [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("Player", inManagedObjectContext: managedContext)
            //Playerエンティティの名前にテキストフィールドの値を設定する。
            player.setValue(testTextField.text, forKey:"name")
            //管理オブジェクトコンテキストの中身を永続化する。
            try managedContext.save()
            //キーボードをしまう
            self.view.endEditing(true)
        } catch {
            print(error)
        }  
        return true
    }
}

を参考に〜〜〜

CoreDataをインポートして〜〜〜
と、コードを組み込むとエラー発生👀

どうやら既に書き方が大分、異なっている様子💦
なので、2時間くらいかかったけど、以下に書き換え〜〜〜〜

今回のコード(まとめ)

class CoreDataStandardViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var myLabel: UILabel!
    @IBOutlet weak var myTextField: UITextField!

    //管理オブジェクトコンテキスト
    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! [NSManagedObject]
            //すべてのPlayerエンティティの名前をラベルに表示する。
            for data in result {
                myLabel.text = myLabel.text! + "," + String(describing: data.value(forKey:"name")!)
            }
            //デリゲート先に自分を設定する。
            myTextField.delegate = self
        } catch {
            print(error)
        }
    }
    //Returnキー押下時の呼び出しメソッド
    func textFieldShouldReturn(_ textField:UITextField) -> Bool {
        do {
            //ラベルの値にテキストフィールドの値を追記する。
            myLabel.text = myLabel.text! + "," + myTextField.text!
            //新しいPlayerエンティティを管理オブジェクトコンテキストに格納する。
            let player = NSEntityDescription.insertNewObject(forEntityName: "Player", into: managedContext)
            //Playerエンティティの名前にテキストフィールドの値を設定する。
            player.setValue(myTextField.text, forKey:"name")
            //管理オブジェクトコンテキストの中身を永続化する。
            try managedContext.save()
            //キーボードをしまう
            self.view.endEditing(true)
        } catch {
            print(error)
        }
        return true
    }
}

⒌シミュレータで実行

と、試行錯誤の結果、ラベルがこれだとみにくいので、、、
ラベルの高さを調整して〜〜〜
てな感じで、改行を押すと追加できた〜〜〜🕺

ブラッシュアップ

AutoLayout

見やすいように背景色と枠線をつけて〜〜〜
文字をデータベースに追加してくだけなので、
上下の位置を逆転させて〜〜〜
てな感じで〜〜〜
あとは適当にpin制約を追加して〜〜〜
コンフリクトが起きたので、修正して〜〜〜
ハイ、完了
だけど、ラベルの色が白のままだね👀謎だ。

地球儀ボタン追加

てな感じでいつもどおり追加〜〜〜🕺

記事公開後、

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

なんだが、実機だとちょっとテキストフィールドの高さがあまりにも狭いので〜〜〜

てな感じで調整した〜〜〜🕺
したら、実機でもバッチリ
(テキストフィールドは相変わらず白なままだが💦)

今回の教訓

当時と比べて、仕様が大幅に変更になってるので、触れたことがない人には、おそらく、今回のサイト記事を見ただけで、中々難しいのでは?👀
って感じ。
現在の仕様は、

なんかを参考にすればいいかなって感じ💦

個人的に詰まったのは、

//すべてのPlayerエンティティの名前をラベルに表示する。
for data in result {
   testLabel.text = testLabel.text! + "," + String(data.valueForKey("name")!)
}

//すべてのPlayerエンティティの名前をラベルに表示する。
for data in result {
    myLabel.text = myLabel.text! + "," + String(describing: data.value(forKey:"name")!)
}

に書き振りが変わってたので、ああでもないこうでもないと悩んだくらい💦
結構、難しいこととか高機能な単体ビューなんかのサイト記事は調べれば山ほどあるんだけど、意外と、

String(data.valueForKey("name")!)

String(describing: data.value(forKey:"name")!)

に変わったみたいな、知ってる人には当たり前のことの方がネットには載っていなかったりするからね〜〜〜〜🤔

知ってて当たり前、自己解決出来て当たり前

で、素通りされちゃうからね👀

独学の人が詰まるのって

  • 本では、簡単すぎる内容か、いきなり小難しいことばかり詳しく書き過ぎている

  • キーワード検索しても、自分が本当に知りたい肝心なところが中々載っていない

  • Swiftの文法と実際のアプリがどう繋がってるかがわかる書き方になっていない

のいずれかで結果、

もういいやって感じになるんじゃないかな〜〜〜

*ま、オイラは所詮、

完全に趣味だから、

心ゆくまま気ままになんであんまり関係ないんだけどね💦

Apple公式

さて、次回は

をレッツゴする🕺

多分、どこかで完全にできないってところが出てきそうな予感大なんだけど、できるところまでは進められたらいいなあ🤔

ここからは、前々回までみたいにハイペースでやらずに、じっくりゆっくりやる〜!
焦る必要もないしねー!

何より、

CoreData(とCloudKit)は、Appleが純正で出してるモバイルデータベース用のフレームワーク
👉連携なんざ意識しなくていいから、何かあった時に調べるコストが減る

キーとバリュー(キーと値)だけで管理していく
👉DB(データベース)の基本をやるのにちょうど良い

これで

これだけビューを組み込んでるデカいプロジェクトでも、

💃普通にCoreDataが動く🕺

てことは証明できたね

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