Realmというものを随分前から聞いたことがありましたが,使ったことがなかったので勉強しました.
Realmの説明とSwiftでRealm Databaseを使ったサンプルをメモします.
Realmとは
「レルム」と読むそうです.
モバイルアプリのデータ保存やデバイス間データ同期をサポートしてくれるもので,3つの製品ラインナップがあります.
Realm Database
- SQLiteやCore Dataの代替になるデータストアライブラリ
- 完全無料で利用できる
- ORMやSQLiteより早いらしい
- 次のようなメリットがある
- 検索が早い
- スレッドセーフ
- クロスプラットフォーム
- 暗号化
- リアクティブ(データの変更がUIに同期できる)
Realm Platform
- Realm Databaseで管理するデータをクラウドでマルチデバイスに同期できるmBaaSサービス
- Realm Database自体がオフラインファーストな作りになっているので,通信が不安定な場合などにもデータの整合性やユーザビリティを担保できる
- データベースだけでなくユーザアカウントの管理やFaaSやAPIブリッジ(他システム連携)なども用意されている
- 使える機能やサポートのレベル別に3つのサービスが用意されている(Developer Editionは無料)
- Developer Edition
- Professional Edition
- Enterprise Edition
Realm Studio
- Realm Platform上のデータを参照したり操作したりできる開発ツール(アプリ)
今回試してみたこと
iOSでプラットフォームに依存しないデータストアを試してみたかったので,Realm DatabaseをSwiftで使ってみました.
Realm Platformを使ったクラウドへの保存やデバイス間データ同期は試していません.
サンプルアプリとして,簡単なTodo管理アプリを実装し,Todoの追加・削除・永続化を行ってみました.
ソースは以下のGitHubリポジトリに置いています.
環境
- Xcode 9.2
- Swift 4.0
- iOS 11.2 (simulator)
- RealmSwift 3.0.2
Realmライブラリのインストール
CocoaPodsでインストールしました.
pod init
し,Podfileにpod 'RealmSwift'
を追記した後で,次のコマンドを実行します.
pod repo update
pod install
pod repo update
を実行しないと古いバージョンがインストールされる場合があるので注意が必要です(私の環境では,実行しない場合は2.7.0がインストールされましたが,実行したあとは3.0.2がインストールされました.)
モデルの作成
モデルはクラスとして実装しますが,次の点に注意です.
- モデルは
Object
(RealmSwiftのクラス)を継承する必要がある - 1:nのモデルはSwiftのArrayではなく,
List
(RealmSwiftのクラス)を使う必要がある(今回のサンプルでは1:nモデルは作っていません) - モデルの定義を変えた後はMigrationをしないとアプリがクラッシュしました
Todoのアイテムモデルを表す次のようなクラスを作りました.
class TodoItem: Object {
@objc dynamic var title = ""
}
Realmへのデータ追加
新規Todoの追加処理は次のように実装しました.
private var realm: Realm!
func addTodoItem(title: String) {
try! realm.write {
realm.add(TodoItem(value: ["title": title]))
}
}
Realmからデータ削除
既存Todoの削除処理は次のように実装しました.
private var realm: Realm!
private var todoList: Results<TodoItem>!
func deleteTodoItem(at index: Int) {
try! realm.write {
realm.delete(todoList[index])
}
}
Realmデータの変更通知
Realm notificationという仕組みで変更通知を受けることができます.
本当はUITableViewのセル挿入やセル除去をきちんとやるべきです(Realmのドキュメントではそうしてます)が,簡略化のために追加削除の場合も一様にreloadData()
をしちゃってます.
private var realm: Realm!
private var todoList: Results<TodoItem>!
private var token: NotificationToken!
@IBOutlet weak var tableView: UITableView!
override func awakeFromNib() {
super.awakeFromNib()
// RealmのTodoリストを取得し,更新を監視
realm = try! Realm()
todoList = realm.objects(TodoItem.self)
token = todoList.observe { [weak self] _ in
self?.reload()
}
}
func reload() {
tableView.reloadData()
}
その他
今回は試していませんが,他にも条件付きクエリやモデル間のリレーション定義,データファイルの暗号化など便利な機能がいっぱいなので,今度試してみたいです.