※これは iOS/Android モバイルデータベース Realm についての記事です。詳しくは以下をご参照ください。
Webサイト: realm.io、Facebookグループ: Realm Japan User Group、質問: Slack Channel
--
☆ 8/13(木)14:00~ に行われた Realm オフィスアワーの質問 & 回答一覧です。
この時点での Realm のバージョンは、それぞれ realm-cocoa 0.94.1 と realm-java 0.82.1 です。ご注意ください。
Realm の今後のロードマップはどこかにまとまっているか?
直近だとWWDC中に行われたミートアップのスライドには載っているが、それは共有されてない。大雑把に言うと今年中(2015年中)に1.0をリリースする。
それに向けて足りない機能(NULL, カスケード削除、非同期クエリ、きめ細かい通知)などが実装される予定である。機能についての予定ならGithubのIssuesを見るのがいい。
Realmでは waffle.io というので一覧して見ている。
waffle.io(realm-cocoa) → https://waffle.io/realm/realm-cocoa
おそらく、ロードマップのスライドは優先順位が変わることが多いため公開していないと思う。
ViewControllerに編集用のデータとしてRealmオブジェクトを持たせるのは良いかどうか?
ViewControllerに表示用と編集用のデータを持たせることは多々ある。これをRealmオブジェクトにすることはできるか?
ドキュメントにも
Can't mutate a persisted array outside of a write transaction."
とあるように、Realmオブジェクトのプロパティを変更する場合はDBに書き込むようにしないとだめなようなので、永続化したくはないけどプロパティをいじったりしつつVCとかに保持しておきたい場合には向いてないと思った。
この点については
・Realmオブジェクトで編集中のオブジェクトを保持する場合は、バックグラウンド保存で編集中のデータが変わってしまうことがあること
・トランザクションが必要になること
・別のオブジェクトなり、VCのプロパティを使う場合は、柔軟性は上がるがオブジェクトのコピーが必要になるというデメリットがある
たいていは編集画面のVCが使う編集用の値を保持するオブジェクトをもつほうが柔軟になるのでそちらを選ぶと良いと思う。Realmに限らず、CoreDataでも同様なのでそうすることが多い。
Realmオブジェクトでやる場合は、Realmに保存されていないオブジェクトなら普通のオブジェクトと同様に扱えるので、initWithValue:
でコピーして、編集結果を保存するならコミット、保存しないならそのまま捨てる、という実装だと簡単。Realm に保存されていないオブジェクトなら各プロパティの変更はトランザクション不要なためその点については問題ない。
Realmに保存されているオブジェクトをそのまま使う場合は、 viewWillAppear:
などでトランザクションを開いて、保存するか、キャンセルするときまで、開きっぱなしにすると実現できる。保存のときに commitTransaction
、キャンセルなら cancelTransaction
で大丈夫。ただ、編集中にバックグラウンドでフェッチして上書き、みたいなケースが発生すると思うので、そういうことがないとわかってるときのみ。
割と大き単位でのトランザクションにする場合は、これ( https://github.com/tokorom/SegueContext )と組み合わせれば楽しそう。一覧で選択したオブジェクトを編集画面で受け取って、編集画面が出てる間はトランザクションが開いている感じにする。
Realmに保存しているテキストに対して検索を行いたい
今、掲示板機能のあるアプリを作成しており、Realmを導入しようか考えている。そこで、掲示板の検索について、記事の中から全文検索で部分一致すればTableViewに記事のタイトルを並べると言った機能を付けたいと思っており、こういった場合はどのようにオブジェクトを取得すればよいか?
Full Text Searchはまだ検討中の機能だが、contains
が十分速いので、それでまずやってみるのがよい。
下記は住所を全文検索する例で、住所程度なら10万件くらいに対して contains で検索しても一瞬で結果が返ってくる。
RLMRealm *realm = [RLMRealm defaultRealm];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"address CONTAINS %@", searchText];
RLMResults *data = [Address objectsInRealm:realm withPredicate:predicate];
掲示板の1件のテキストの分量によるが、200〜400文字くらいだと思うので十分な速度で動くと思う。時間がかかるようならバックグラウンドで検索するなどが必要になるが、おそらく大丈夫。
非同期でのRealmの更新について
上記のリンク先のコードで、別のスレッドでオブジェクトの追加を行っているのに、メインスレッドでそれが反映されない。-[RLMRealm refresh]
を呼んでみるとうまくいった。
原理的には別スレッドの変更はトランザクションがコミットされた時点で、他の同じRealmに変更が通知されます。
ただ、それが遅れる場合がある、というか今回だと、メインスレッドは制御を戻さないので、いったんこのメソッドを抜けるか、ランループに制御を戻さないと、変更を受けられないと思う。
あるいは、普通に非同期のタイミングで変更通知が、読み取りより遅くなることはある。よって、タイミングが問題のときはあえて refresh()
を呼んで、古いデータが返ってくるのを防ぐことができる。毎回 refresh()
を呼ぶようなラッパーやエクステンションを作ってる人もいたと思う。毎回である必要はないと思うが、更新ボタンを押したあとなど、確実に新しいデータを出さないとユーザーが混乱する場合は呼んでおいたほうがよい。
realm-java の新しいマイグレーションAPIはいつ実装されるのか?
実装はほぼ済んでいて、APIのレビューもだいぶ進んでいるので、それほど時間はかからないと思う。
以下が関連するPullRequest
https://github.com/realm/realm-java/pull/1239
https://github.com/realm/realm-java/pull/1253
https://github.com/realm/realm-java/pull/1265
Javaチームのミーティング議事録を見たが次のリリースに含めることができるもののリストに入っていた。
--
デベロッパーの Realm オフィスアワーは月に一度、Slack で開催していますが、オフィスアワー関係なくいつでもご質問ください。
Realm Slack Channel → http://slack.realm.io/