なぜ Realm を使うのか改めて振り返る

  • 33
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Realm の Advent Calendar を見ていると、だいたいみんな同じようなことを考えて対処しているんだなあ、と感じます。

ここでは、改めてなぜ Realm を使うのか(使ったのか)というところを振り返って書いてみたいと思います(なお、iOS アプリ開発で、Obj-C/Swift 混在環境で使いました)。

なぜ Realm を使うのか

まず、そもそも、スマートフォンアプリにデータベースが必要なのでしょうか?

データベースって、特定の状況では便利なものだけど、一方で面倒なことも多いもの、というイメージがあるかと思っています。解決したい問題がちょっとしたものだったりすると、そのためにデータベースを導入するのは大袈裟すぎるのでは? スマートフォンアプリ内部にわざわざデータベースを内蔵するのか? という感じもします。

実のところ、データベースが欲しい、というよりも、次のような問題を解決する手段が欲しい、という望みがあります。

  • アプリ内で使うオブジェクトをストレージに永続化したい。
    • 例えば、オンラインの場合はサーバからデータを取得するが、オフラインの場合はストレージにあるものを使いたい。あるいはキャッシュ的な用途。
  • 永続化したオブジェクトに簡単にアクセスしたい。
    • 永続化したオブジェクトにアクセスするとき、何らかの展開・変換をしないと使えないようなものはつらい。

これを実現する有力な手段として、データベースを使うという手段があると考えています。言ってしまえば、その程度のことなので、導入や実装に労力がかかりすぎるとつらいわけです。

そこで、Realm が良い、という話になります。

導入は、他の一般的なライブラリと同じです。実装も、Realm で扱うオブジェクトは普通のアプリのモデルオブジェクトと同じような感覚で実装できて、簡単です。そして、永続化するのが簡単で、アクセスも簡単。欲しい要件が満たされています。

さらに言えば、アプリ内の Realm ファイルを外部に取り出して Realm Browser アプリで簡単に見れるので、デバッグやテストでも都合が良いです。

Realm を使ううえでの注意点

Realm のオブジェクトを扱う場合に、普通のオブジェクトと扱いが違う点には注意を払う必要があります。

  • オブジェクトを変更する場合はトランザクションの中で行う。
  • 別スレッドにオブジェクトを渡すことはできない。

データベースなんだから普通そうだろう、という注意点です。しかし、データベースを使うというよりも永続化にちょっと便利なライブラリを使うという感覚で Realm を使うわけなので、改めて意識を払っておいたいポイントです。

特に後者は、個人的にはよく引っかかりました。将来的には Realm が対応してくれるらしいということで期待しています。

実装時によく使ったパターン

別スレッドにオブジェクトを渡すというのはやはり行いたいところです。対策としては、Realm のオブジェクトを別のオブジェクトに変換するという方法を、個人的には採用しています。通常の struct の static メソッドに次のようなものを定義して使いました。

struct Hoge {
    let param1: Int
    let param2: String
    ...

    static func fromRealm(object: RealmHoge) -> Hoge {
        return Hoge(
            param1: object.param1,
            param2: object.param2,
            ...
        )
    }
}

と言っても、Realm のオブジェクトをメインスレッドで使いたい場合に、単にそのメインスレッドで Realm のクエリを呼び出して使うようにしている箇所もあります(クエリが高速に動作するので、わざわざ専用のスレッドでクエリしなくても事足りる)。

(なお、以前 Realm meetup で発表した Realm と RxSwift のパターンは、今回は諸事情で使っていません・・・。普通に、RxSwift の subscribe の中で Realm のクエリを行うようにしました)

また、Web API から JSON で渡されるデータをそのまま Realm に保存したい、という場合があったので、APIKit と Himotoki との組み合わせで次のような感じで対処しました。

struct GroupRequest: AppAPIRequest { // <- APIKit
    func responseFromObject(object: AnyObject, URLResponse: NSHTTPURLResponse) -> Response? {    
        let response = try? decode(object) as Response // <- Himotoki
        if let response = response {
            dispatch_async(AppRealm.sharedInstance.queue) {
                let realm = try! RLMRealm(configuration: AppRealm.sharedInstance.configuration)
                realm.transactionWithBlock {
                    realm.addOrUpdateObjectsFromArray(response)
                }
            }
        }
        return response
    }
}

まとめ

Realm のおかげで、データベースに対する抵抗というか苦手意識みたいなものがだいぶ軽減された、と個人的には思いました。Realm の今後に期待しています。