Realmとは、、、
一言で言うとデーターベース。
iOSアプリでデータを保存したい時に使用されます。
データ保存は、Realmの他にUserDefaultsやCoreDataが用いられる事もあります。
CoreDataよりも直感的に利用でき、動作も速いことが特徴。
Swiftに対応したRealmSwiftがあるため、今回は使用していきます。。
以下、ドキュメント
Realm
アプリ作成
環境
- Xcode 10.1
- Swift 4.2
- Cocoapods 1.5.3
ソースコード
gitHubにあげているので、全体のコードはこちら。
shun6934/DiaryApp
参考サイト
Realmの導入
1. Cocoapodsの導入
今回は、CocoapodsでRealmを管理します。
Cocoapodsは、Rubyが必須ですが、
Macではデフォで入っているため気にしなくていいです。
以下のコマンドを叩いて、インストールします。
$ sudo gem install cocoapods
正しくインストールされていれば、
$ pod --version
でversionを確認できます。
2. プロジェクト作成
Xcodeを開き、
Create a new Xcode project -> Single View App
で作成。
アプリ名は、Diary_App
としておきます。
3. Podfile
ターミナルを開き、先ほど作成したアプリのディレクトリまで移動した後、
$ pod init
でPodfileを作成し、
$ vi Podfile
で編集します。
今回は、データを保存したいため、データベースであるRealmをSwiftで使うためのRealmSwift
と
カレンダーを表示するためのJBDatePicker
をライブラリーとして用います。
# Uncomment the next line to define a global platform for your project
# platform :ios, '12.1'
target 'Diary_App' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# 以下、追加
pod 'JBDatePicker'
pod 'RealmSwift'
# Pods for Diary_App
end
編集できたら保存し、
$ pod install
を行ないます。
警告は出ていますが、無事にインストールされています。
これで準備できたので、これからコードを書いていきます。
カレンダー表示
1. Viewの配置
Main.storyboard
を開き、
カレンダーを表示したいViewControllerにView
を配置します。
次に、先ほど配置したViewに対してJBDatePickerView
Classを定義します。
Moduleに関しては、Classを入力した際に決まるため、入力する必要はありません。
2. コードの紐付け
Storyboardに配置したViewをコードに紐付けさせる必要があります。
Viewを選択した状態で、Ctr
を押しながらコード上に引っ張っていきます。
変数名は、datePickerView
とします。
これだけではエラーが出るため、モジュールをimportする必要があります。
また、Delegateプロトコルを宣言する必要があります。
import UIKit
import JBDatePicker // import
class ViewController: UIViewController, JBDatePickerViewDelegate { // Delegete宣言
@IBOutlet weak var datePickerView: JBDatePickerView! // カレンダー
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
datePickerView.delegate = self // DelegateをControllerに追加
}
// 日付選択時
func didSelectDay(_ dayView: JBDatePickerDayView) {
print("day selected:\(dayView.date!)")
}!
}
ここで一旦実行してみましょう。
しっかりとカレンダーが表示されていたらokです。
また、任意の日付をタップすると
コンソールに日付が表示されると思います。
3. 日付の表示
コンソールに表示された日付は、タイムゾーンを無視しているため、
それを考慮する必要があります。
以下のコードを追加して、日本の日付にします。
lazy var dateFormatter: DateFormatter = {
var formatter = DateFormatter()
formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMM",
options: 0,
locale: Locale(identifier: "ja_JP"))
formatter.timeZone = TimeZone(identifier: "Asia/Tokyo")
return formatter
}()
日付を変更できたため、didSelectDay
を書き換えます。
func didSelectDay(_ dayView: JBDatePickerDayView) {
print("day selected:\(dateFormatter.string(from: dayView.date!))")
}
もう一度実行すると、コンソールはこのように変化します。
day selected:2018年12月5日
データベースの構築
1. モデルの用意
File -> New -> File
で新規ファイルを作成。
CocoaTouch
を選択し、名前をDiary
、SubClassをObject
にしたら、
保存します。
作成した後は、Objectでエラーが出るため、
RealmSwift
をimportします。
import RealmSwift
class Diary: Object {
}
2. モデルの構成
日記に必要な情報は、「日付」と「本文」です。
日付と本文は、String型
です。
Primary Keyとしてdate
を設定します。
@objc dynamic var date: String = ""
@objc dynamic var context: String = ""
open var primaryKey: String {
return "date"
}
データーベースのモデルができたため、日記を打ち込む画面を作成します。
日記
1. 日記画面
Main.storyboard
で以下のように画面を作成します。
新しい画面の追加に伴い、ファイルも作成しておきます。
カレンダー表示と同様に、LabelやTextViewの紐付けをします。
import UIKit
import JBDatePicker
class ViewController: UIViewController, JBDatePickerViewDelegate {
@IBOutlet weak var datePickerView: JBDatePickerView!
@IBOutlet weak var writeButton: UIButton! // 追加
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
datePickerView.delegate = self
}
func didSelectDay(_ dayView: JBDatePickerDayView) {
print("day selected:\(dayView.date!)")
}
// 追加
@IBAction func writeButtonPushed(_ sender: UIButton) {
}
}
import UIKit
import RealmSwift //ここでRealmを使う
class DiaryViewController: UIViewController, UITextViewDelegate { //Delegate宣言
// 紐付け
@IBOutlet weak var dateLabel: UILabel!
@IBOutlet weak var contextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// TextViewの設定
contextView.delegate = self
contextView.layer.borderColor = UIColor.black.cgColor
contextView.layer.borderWidth = 1.0
contextView.layer.cornerRadius = 10.0
contextView.layer.masksToBounds = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 「保存」ボタンを押した時の処理
@IBAction func saveButtonPushed(_ sender: UIButton) {
}
}
2. データの受け渡し
日記画面の日付に、カレンダー画面での日付を渡さなくてはいけないため、
date
として渡してあげます。
まず、受け渡し元のViewControllerで以下のコードを書きます。
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
}
}
segue
を設定したため、Storyboardでも設定します。
次に、受け渡し先であるDiaryViewControllerに受け皿を用意してあげます。
困惑しないように、変数名を統一します。
var date: String! // 受け皿の用意
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
dateLabel.text = date // Labelに日付を表示
}
これで日付の受け渡しができたため、
本文に書いた内容を保存していきます。
3. Realmに保存
保存したいタイミングが「保存」ボタンが押されたときであるため、
先ほど紐付けたメソッドに書いていきます。
// 「保存」ボタンを押した時の処理
@IBAction func saveButtonPushed(_ sender: UIButton) {
let realm = try! Realm() // Realmの初期化
let diary = Diary() // モデルのインスタンス化
diary.date = date
diary.context = contextView.text
try! realm.write {
realm.add(diary, update: true) // Realmに追加
}
self.dismiss(animated: true, completion: nil) // 前の画面に戻る
}
値がきちんと保存されているか確認するために、
Realm Browserで確認します。
確認方法は、以下のサイト参考。
【Swift】Realm BrowserでRealm Mobile Databaseの中身を確認する
4. Realmからの値の読み込み
過去に書いた日記を表示したいため、値を読み込み、表示する必要があります。
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.contextView.text = context
}
}
}
}
完成
これでできたため、実行してみましょう。
以下になったら、完成です。
更新
この記事で一つ欠点があったので、修正します。
コメントでのご指摘ありがとうございます。
カレンダー表示時に、日付をタップせずにそのまま書き込むボタンを押してしまうと
アプリが落ちてしまいます。
原因は、date