[Swift3]個人アプリでRealmを実装してみた

今日も朝からジムでふんふんとバーベルを持ち上げてから開発をしております。
筋肉エンジニアのたくです。

前回投稿した[[swift3]RealmSwiftを使ってシードデータを作成し、アプリ内検索機能を実装する](http://qiita.com/takuyama29/items/5940583e98a1c1f577a1)に引き続き、個人でリリースした[**PFCボディメイク**](https://itunes.apple.com/jp/app/pfc%E3%83%9C%E3%83%87%E3%82%A3%E3%83%A1%E3%82%A4%E3%82%AF/id1274048262?mt=8)で活用したRealmについて書きたいと思います。

# Realmとは
公式サイトの[Get Started](https://realm.io/jp/docs/swift/latest/#section-20)では以下の様に書かれています。

```
The Realm Mobile Platform

The core concept of the Realm Mobile Platform is a lightweight object container called a Realm. Like a database, data in Realms can be queried and filtered, interconnected, and persisted. Unlike a traditional database, though, objects in Realms are live and fully reactive. Realms synchronize seamlessly between devices and applications, and can be accessed safely across threads.
```
```
The Realm Mobile Database

The Realm Mobile Database is built from the ground up to run on mobile devices. Unlike a traditional database, objects in a Realm are native objects. You don’t have to copy objects out of the database, modify them, and save them back—you’re always working with the “live,” real object. If one thread or process modifies an object, other threads and processes can be immediately notified. Objects always stay in sync.

The Realm Mobile Database is open source (using the Apache license) and cross-platform, with libraries available for Android, iOS, Xamarin (.NET), and React Native. Realms are fully interchangeable between platforms.

You can use the Realm Mobile Database all on its own. But to take full advantage of the Mobile Platform, pair it with the Realm Object Server.
```

Google先生

```
レルム・モバイル・プラットフォーム

Realm Mobile Platformのコアコンセプトは、Realmという軽量オブジェクトコンテナです。データベースと同様に、レルム内のデータは照会、フィルタリング、相互接続、永続化が可能です。しかし、従来のデータベースとは異なり、Realmsのオブジェクトは完全に反応しています。レルムはデバイスとアプリケーション間でシームレスに同期し、スレッド間で安全にアクセスできます。
```


```
レルムモバイルデータベース

レルム・モバイル・データベースは、モバイル機器上で動作するように基本から構築されています。従来のデータベースとは異なり、レルム内のオブジェクトはネイティブオブジェクトです。オブジェクトをデータベースからコピーして変更し、元の状態に戻す必要はありません。常に「実際の」実際のオブジェクトで作業しています。あるスレッドまたはプロセスがオブジェクトを変更すると、他のスレッドやプロセスに即座に通知することができます。オブジェクトは常に同期しています。

レルムモバイルデータベースは、オープンソース（Apacheライセンスを使用）とクロスプラットフォーム、Android、iOS、Xamarin（.NET）、React Nativeで利用可能なライブラリを備えています。レルムはプラットフォーム間で完全に互換性があります。

レルム・モバイル・データベースはすべて単独で使用できます。しかし、モバイルプラットフォームをフルに活用するには、Realm Object Serverとペアにします。
```

つまり、Realmはアプリ内にデータベースを持ち、データ更新の際には常にデータベースと同期されて最新の状態になっている。またデータの取扱の処理も早いということかと。


# 使い方
基本的な使い方としてはこんな感じです。

1. SDKのインストール
2. モデルクラス作成
3. データの読み書き
4. Realm Browserでデータの確認

### 1. SDKのインストール
インストール方法はCocoaPods、Carthage、フレームワークの直接インポートの3通り。
現在(2017年9月4日時点)での最新バージョンは2.10.0となっています。

僕は普段使いのCocoaPodsを利用しました。詳細は[インストール](https://realm.io/jp/docs/swift/latest/#section-2)を参照。

```
target 'AppName' do

    pod 'RealmSwift'

```

インストール後は`.xcworkspace`からプロジェクトを起動して作業を行っていきます。

### 2. モデルクラス作成
Realmは特にセットアップなどを行う必要は無いのですが、プロジェクト内でデータの処理を行いためにはデータモデル用のクラスを作成する必要があります。

また、RealmSwift SDKをインストールするとプロジェクト内のファイル作成候補に `Realm Model Object` というファイルが出てくるので、データモデルクラス用のファイル作成時にはこれを選択してファイルを作成します。

<img width="1057" alt="Screen_Shot_2017-09-04_at_13_08_57.png" src="https://qiita-image-store.s3.amazonaws.com/0/143619/45bfb139-9bc4-9264-d0c1-882b947cb4b3.png">

データモデルは以下の様にObejectクラスを継承して作成。

```
import RealmSwift

// 食事記録クラス
class MealRecord: Object {
    dynamic var mealName = ""
    dynamic var protein = 0
    dynamic var fat = 0
    dynamic var carbohydrate = 0
    dynamic var calorie = 0
    dynamic var basicAmount = ""
    dynamic var ingestionTime = Date()
    dynamic var objectId = ""
    dynamic var mealType = 0
    dynamic var adjustRate = 0
}
```


### 3. データの読み書き
Realmではデータモデルクラスのオブジェクトを生成する際に`.filter()`メソッド内に引数を指定することにより、任意のデータベース内にあるデータの読み込み(検索)を行うことができます。

```
let realm = try! Realm()

// ingestionTimeカラムの値がstartPoint ~ endPointとなっているデータを検索
let todaysMealLatestObject = realm.objects(MealRecord.self).filter("ingestionTime BETWEEN {%@, %@}", startPoint, endPoint)
```
クエリは上記の様に第一引数に検索するカラムと条件を、第二引数にクエリで使用する変数を指定します。

他にもさまざまなクエリがあるので、詳細は[NSPredicate Cheatsheet](https://academy.realm.io/posts/nspredicate-cheatsheet/)を参考にしてみてください。

また、`.filter()`メソッドを指定しない場合は、データモデルクラスのレコードが全て出力される様になっています。

```
let realm = try! Realm()

// MealRecordのレコードを全件出力
let todaysMealLatestObject = realm.objects(MealRecord.self)
```

データベースへの書き込みする際には、生成したデータモデルオブジェクトのプロパティに対して追加したい値を割り当てていきます。

```
// データモデルクラスのオブジェクトを生成
let mealRecord = MealRecord()

// それぞれのカラムに相当するプロパティに対して値を割り当てる
mealRecord.mealName = "おにぎり"
mealRecord. protein = 2
mealRecord.fat = 0
mealRecord.carbohydrate = 39
mealRecord.calorie = 179
mealRecord.basicAmount = "100g"
mealRecord.ingestionTime = Date()
mealRecord.objectId = NSUUID().uuidString
mealRecord.mealType = 0
mealRecord.adjustRate = 0
```

それぞれのカラムに割当てを行った後に、Realmクラスを継承したオブエクトに対して`write()` メソッドを行うことで当該のデータを書き込むことができます。

```
try! realm.write {
    realm.add(notificationSettings2)
}
```

また、[オブジェクトの更新](https://realm.io/jp/docs/swift/latest/#section-23)や、[オブジェクトの削除](https://realm.io/jp/docs/swift/latest/#section-27)などもあるので興味のある方はどうぞ。


### 4. Realm Browserでデータの確認
最後に、書き込みや更新などを行った後に実際に意図したデータが`.realm`ファイルに保存されているかを確認します。

Realmでは、Realm Browserという便利なクライアントアプリがあるので、これを使って確認します。

クライアントアプリは[こちら](https://itunes.apple.com/app/realm-browser/id1007457278)からダウンロードできます。

また、[Xcode Plugin](https://realm.io/jp/docs/swift/latest/#xcode-plugin)を使う方法もあるので、より都合の良い方でお試しください。

僕はRealm Browserを使っているのですが、自分がデータを保存した`.realm`がどこにあるのかを見つけるのにちょっと手こずりました。。

もしファイルが見つからない場合は、以下を参考にするとよいかと思います。

[stack overflow Realm Browserの使い方](https://ja.stackoverflow.com/questions/8592/realm-browser%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9)
[目的のRealmDBの中身をRealmBrowserで一瞬で開く方法](http://qiita.com/gologo13/items/5cb94ffd67e3b09f7678)

これで更新したデータを確認する事ができます。

<img width="1278" alt="Screen_Shot_2017-09-04_at_18_01_47.png" src="https://qiita-image-store.s3.amazonaws.com/0/143619/513013f8-da32-f1fc-b020-b2a4dcc23080.png">

また、Realm Browserからレコードの削除もできるでのとても便利です。

ぜひ試してみて下さい。