LoginSignup
36
32

More than 5 years have passed since last update.

Swiftで日記アプリを作ろう 〜その3 Realm活用編〜

Last updated at Posted at 2017-01-03

前回の記事はこちら

いよいよRealm活用編!
値を保存する方法をマスターしましょう!

Realmの導入がまだの方はこちらから。

1. モデルファイルを作成

Realmデータベースを使うために、まずはモデルを作成しましょう。
新規ファイルを追加するときにいつも行っている「New File...」を選択します。
image

Realm Pluginが正しく導入されていれば、下にスクロールすると「Realm Model Object」が表示されています。選択して次へ。
image

Model Object Classには、「Diary」と入力。
image

最後に、「Create」ボタンをクリックして完了です。
image

2. モデルファイルの中身を考える

いま、Objectクラスを継承した「Diary」クラスを作成しました。今度はこの中身を考えていきましょう。

いま、データベースの枠を作っているものと思ってください。
日記アプリにはどの要素が必要でしょうか?

今回は、以下のようなデータベースを作成することを目標にしていきます。
image

※どうでもいいですが、筆者の実話です。

そこで、今回は一番上の部分を考えていきます。
もし要素がほかにもあるようなら、自分で追加してかんがえてみてください。

このデータベースの中身ではなく枠の部分(今回は青い背景の部分)を「エンティティ」といいます。
データベース設計を考えるときにはエンティティの設計がとても大事です。

今回は「日付」「本文」「写真」と3つのエンティティがありますが、それぞれのエンティティに名前と型をつけていきましょう。

image

それでは、上図のとおりにDiary.swiftにモデルを定義していきます。
上図のような表はデータベースを設計するときはかならず作りましょう!
Google Spreadsheetや、Excelのような表で構いません。あとで自分がコードを見たときに思い出しやすくなります。

Diary.swift
//
//  Diary.swift
//  DiarySampler
//
//  Created by Ryo Eguchi on 2017/01/02.
//  Copyright © 2017年 Ryo Eguchi. All rights reserved.
//

import Foundation
import RealmSwift

class Diary: Object {
    dynamic var date = ""
    dynamic var context = ""
    dynamic var photo: NSData? = nil

    override static func primaryKey() -> String? {
        return "date"
    }

}

dateをPrimary Keyとして設定しました。Primary Key(以下、「PK」)として設定することで、一意性を保ちます。(重複してはいけないという意。)
※画像はその4で扱います。

それぞれのエンティティの作成方法は、チートシートを参考にしてください。

3. 日記作成画面の設置

Storyboardで、日記作成画面を作りましょう。
image

関連付けもわすれずにしておきましょう。

ViewController.swift
    @IBOutlet var writeButton: UIButton!

// (中略)

    @IBAction func writeButtonPushed(_ sender: UIButton) {


    }

続いて、2番目のViewController(DiaryViewController)についても同様に関連付けします。
あらかじめNew File...で新しくViewControllerファイルを作っておきましょう。

DiaryViewController.swift
//
//  DiaryViewController.swift
//  DiarySampler
//
//  Created by Ryo Eguchi on 2017/01/02.
//  Copyright © 2017年 Ryo Eguchi. All rights reserved.
//

import UIKit

//このファイル内でRealmを使うのでここを追加
import RealmSwift

class DiaryViewController: UIViewController {

    @IBOutlet var dateLabel: UILabel!

    @IBOutlet var contextTextView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func saveButtonPushed(_ sender: UIButton) {
    }

}

4. 情報をDiaryViewControllerに集約させよう

今回のアプリの構造は次のとおりです。
image

つまり、すべての情報が「DiaryViewController」に集約され、そこから情報がRealm Databaseに格納されます。
そこで、情報をすべてDiaryViewControllerに集約させましょう。

4-1. dateの受け皿を準備する

DiaryViewControllerに、dateの受け皿を準備しましょう。
変数を宣言します。

DiaryViewController.swift
    var date: String!

実際にラベルに表示させるようにしておきましょう。

DiaryViewController.swift
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        dateLabel.text = date

    }

4-2. 受け渡し元のViewControllerで処理を記述

ViewController.swift
    var date: String!

    // (中略)

    func didSelectDay(_ dayView: JBDatePickerDayView) {
        print("date selected: \(dateFormatter.string(from: dayView.date!))")
        date = dateFormatter.string(from: dayView.date!) //追加

    }

    @IBAction func writeButtonPushed(_ sender: UIButton) {
        self.performSegue(withIdentifier: "toDiary", sender: nil)
    }


    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "toDiary") {
            let diaryView = segue.destination as! DiaryViewController
            diaryView.date = self.date
        }
    }

まずはじめに、dateをString型で宣言しておきます。

1つめのメソッド「didSelectDay」は、JBDatePickerDayViewのDelegateメソッドです。
dateにstring型で日付を挿入しています。

2つめのメソッド「writeButtonPushed」は、「書く」ボタンをおした時のメソッドで、画面遷移のコードを書いています。

3つめのメソッド「prepare for segue」は、画面遷移するときに必ず呼ばれるメソッドです。(知らなかったら覚えておこう!)
今回は、「toDiary」の画面遷移をするときに、遷移先のdateという変数に遷移元の変数dateの値を代入します。これで、画面遷移したときに遷移先のdate変数に初期値がセットされました。

4-3. Storyboardで画面をつなげる

Storyboardで1つめの画面と2つめの画面をつなげておきましょう。
Identifierは「toDiary」と記述します。
image

これで、保存はされませんが、シミュレータで実行して画面遷移ができることを確認しましょう。

image

ただしく実行できれば、上図のように画面上部のラベルに日付が表示されます。

5. Realmに保存

最後に、Realmに保存(書き込み)しましょう。

DiaryViewController.swift
    @IBAction func saveButtonPushed(_ sender: UIButton) {

        // STEP.1 Realmを初期化
        let realm = try! Realm()

        //STEP.2 保存する要素を書く
        let diary = Diary()
        diary.date = date
        diary.context = contextTextView.text

        //STEP.3 Realmに書き込み
        try! realm.write {
            realm.add(diary, update: true)
        }


        //画面遷移して前の画面に戻る
        self.dismiss(animated: true, completion: nil)

    }

この地点でRealmに値を書き込んでいるので、きちんと値が書き込まれているかRealm Browserで確認してみましょう。
確認方法はこちらの記事が参考になります。
【Swift】Realm BrowserでRealm Mobile Databaseの中身を確認する

6. Realmから値を読み込む

もし、すでにRealmに値がある場合は、Realmから本文を取ってくるようにしましょう。

DiaryViewController.swift
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        dateLabel.text = date

        DispatchQueue(label: "background").async {
            let realm = try! Realm()

            if let savedDiary = realm.objects(Diary.self).filter("date == '\(self.date!)'").last {
                let context = savedDiary.context
                DispatchQueue.main.async {
                    self.contextTextView.text = context
                }
            }
        }

    }

DispatchQueue(label:"background")では、メインスレッドではなくバックスレッドで処理を実行しています。これをすることで、メインスレッドの処理に影響することなくバックスレッドでQueue(検索して読み込み)を行うことができます。

let savedDiary = realm.objects(Diary.self).filter("date == '\(self.date!)'").last

これは、

realm.objects(Diary.self)

ここで、Diaryオブジェクトをすべて読みこんでいます。そこに、

.filter("date == '\(self.date!)'")

filter(フィルタ)をかけてあげます。今回は、dateエンティティが「self.date!」(選択した日付)と等しいものをすべて読み込んでいます。

さらに、

.last

これで、フィルタをかけたオブジェクトのうちで一番最後(最新)のもの、という意味です。

DispatchQueue.main.async {
   self.contextTextView.text = context
}

これは、DispatchQueueで処理するスレッドを変えていますが、画面表示に関わることなのでバックスレッドでは処理できません。そこで、あえてメインスレッドに変えて処理を実行しています。

36
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
32