iOS
Swift
Realm

SwiftでRealm Databaseを使ってみた

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 Edisionは無料)
    • Developer Edision
    • Professional Edision
    • Enterprise Edision

Realm Studio

  • Realm Platform上のデータを参照したり操作したりできる開発ツール(アプリ)

今回試してみたこと

iOSでプラットフォームに依存しないデータストアを試してみたかったので,Realm DatabaseをSwiftで使ってみました.
Realm Platformを使ったクラウドへの保存やデバイス間データ同期は試していません.

サンプルアプリとして,簡単なTodo管理アプリを実装し,Todoの追加・削除・永続化を行ってみました.

アプリの動作は次のような感じです.
screenshot.gif

ソースは以下のGitHubリポジトリに置いています.

ottijp/RealmFirstTry

環境

  • 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のアイテムモデルを表す次のようなクラスを作りました.

TodoItem.swift
class TodoItem: Object {
  @objc dynamic var title = ""
}

Realmへのデータ追加

新規Todoの追加処理は次のように実装しました.

TodoListViewController.swift
private var realm: Realm!

func addTodoItem(title: String) {
  try! realm.write {
    realm.add(TodoItem(value: ["title": title]))
  }
}

Realmからデータ削除

既存Todoの削除処理は次のように実装しました.

TodoListViewController.swift
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()をしちゃってます.

TodoListViewController.swift
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()
}

その他

今回は試していませんが,他にも条件付きクエリモデル間のリレーション定義データファイルの暗号化など便利な機能がいっぱいなので,今度試してみたいです.