RealmのConfiguringで何が設定できるのか

はじめに

長年食わず嫌いをしてきたCoreDataをようやく使ってみましたが、ユーザデータを保存しておく方法は当然CoreDataだけではありません。ローカルに保存するファイルベースの方法から、クラウドサービスまでよりどりみどりです。

今回はかなり昔に使ったRealmを復習も兼ねてSwiftで使ってみます。

具体的な使い方は世の中にたくさん出ていますので、局所的な説明になります。ライブラリをCocoaPodsかCarthage、zipなどで入れたあと最初の初期化設定の話です。データの読み書きまでは至りませんのでご了承を!

シンプルお手軽な初期化

let realm = try! Realm()

これだけでdefault.realmというデータベースファイルが作られてデータの読み書きができる状態になります。このファイルが存在する場所はデバッグ時実機実行時などで変わりますので、ログを出して見ると良いと思います。

初期化時にいろいろ設定したい

シンプルお手軽な方法はシンプルすぎて、実務上では逆に扱いづらいかもしれません。例えばデータモデル別に保存しておきたい場合など、データベースファイルを複数扱いたいときとかあるじゃないですか?

そこでconfigureの出番です。
公式サイトのConfiguringに関するドキュメントを参照すると、var config = Realm.Configuration()とあります。このconfigに設定ができそうです。

arrow-right
Atlas Device SDK is an offline-first, cloud-syncable database for mobile, web, desktop, and IoT apps.

参考までに、このConfiguration()Realmをインポートしたときには現れません。RealmSwiftをインポートしたときに現れます。

もしプロジェクト(ワークスペースではない)内にSwiftとObjective-Cが混在しているときで、Objective-Cにて初期化するときはRealmをインポートして、

RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];

としてください。
最近Objective-Cを書く機会が無いので合っているかわかりませんが、多分大丈夫でしょう。Swiftではあまり気にしてなかったですけど、Objective-Cでは確保して初期化の流れをせっせとしてましたよね。

あとはこのconfigをRealmのインスタンスを作るときに渡すだけです。

let realm = try! Realm(configuration: conf)

最初Swiftだけのプロジェクトでimport RealmとしていてConfiguration()が使えず、公式ドキュメントの誤りにしばらく悪態をついていたのは内緒です。ほんとにごめんなさい。
蛇足ですが、Swiftだけのプロジェクトでもimport Realmvar config = Realm.RLMRealmConfiguration()でOKのようです。

設定できる項目の再確認

ざっと概要

さて、Configurationできるようになったところで、何が設定できるのか見ていきましょう。アルファベット順で並べました。効果は私の理解力で把握したものです。

よく使いそう?項目効果
deleteRealmIfMigrationNeededマイグレーションの度にデータベースファイルを消すかどうか
encryptionKeyデータベースファイルを暗号化するためのバイト文字列を与える
fileNameデータベースファイル名を設定する
inMemoryIdentifierインメモリでデータベースを展開するときに使う名前を設定する
ファイルベースのときのデータベースファイル名代わりのもの
migrationBlockバージョン間でのマイグレーションの内容を書く
readOnlyデータベースファイルを読み取り専用とするかどうか
schemaVersionスキーマのバージョンを指定する
shouldCompactOnLaunchデータベースファイルがブクブク太ったときに小さくするかどうか
×syncConfiguration同期的ななにかをあれする

まずは○印のものはほぼ必須ですね。migrationBlockschemaVersionは、Configurationで書くと長くなってしまいますので別枠で書いておいたほうが良いでしょうね。その方が管理しやすいかと思います。

△印は必要に応じて使うというところでしょうか。×印のは当面の間要りません。
リアルタイム同期とか実に興味深いですが、またの機会にしましょう。

深掘り:データベースの暗号化

RealmはデータベースがAccessやSQLiteのようにファイルベースなので扱いやすいです。その反面、データを抜かれやすいという欠点があります。ファイルをパッケージの中からヒョイッと取り出せば良いのですから。
デバッグでは便利ですが、お呼びでない方々にとっても便利ということです。その観点から、暗号化は非常に有用です。

ただし、暗号化のためのキーはアプリ内に持たないといけません。キーをキーチェーンに入れたりなど、実際に使う際はキーが簡単にわからないようにしておく工夫が必要になります。

参考までに、Realm公式Githubにて見つけたサンプルプロジェクトです。

realm-swift/examples/ios/swift/Encryption at master · realm/realm-swift
Realm is a mobile database: a replacement for Core Data & SQLite - realm/realm-swift

深掘り:インメモリ展開の注意点

データベースの内容をメモリ展開しておくとファイルIOがなくなる分動作が軽快になります。

ただしこれも注意点がありました。まず、メモリ上にしかデータが存在しないため、何かの拍子にアプリが落ちたりしたときにデータが全て消えます。一時的に保持しておくだけならともかく、必要に応じてファイルにバックアップを取ったりしておく必要があります。

また、Realmのインスタンスがなくなった時点でメモリ上からなくなる可能性があります。ざっくり言うと、参照が切れたあとでGCさんにお掃除されてしまうということですね。アプリが生きている間やデータ必要な間は、参照を切ってはいけないということになります。
意外と重要な点かもしれません。

まとめ

自分が使いやすいアプローチを見つける

シンプルにtry! Realm()でも良いのですが、自分の型というかアプローチパターンというかルールを作っておくと扱いやすいですね。

ちなみに私の場合で適当に思いつく点としては、

  • 面倒臭くてもdo-try-catchを使う
  • configureを別途設定しておいて、Realmのインスタンスを生成するときに渡してあげる
  • マイグレーションは別クラスに切り出ししてしまう

ぐらいでしょうか?

これから

それと今回は触れていませんが、データベースを読み書きする処理も別クラスを切り出したいですね。

依存性の向きをうまいこと逆にしてやれば、データベースをRealm以外にしたいときに読み書き処理クラスを差し替えるだけで対応できるんじゃないかと目論んでいます。今までまともに試してみたことは無いのでうまくいくかわからないですが、いずれマジメに書きたいと思います。

注意事項

毎度おなじみになりそうですが、免責的なことを。

ここに書いていることは無保証であり、主張の押し付けではありません。
あくまでも1つの方法として捉えていただければ幸いです。
お試しの折は公式サイトやその他の情報ソースなどもご参照くださいませ。

また、もし組織に所属されていらっしゃる場合は、組織の御意向などには適宜従っておいたほうが良いと思います。

間違いを見つけた(指摘された)ときは、記事内容の修正を適時行うかもしれません。