ネストしたオブジェクトも監視したい
どうやらコレクションの監視のmodificationは、ネストしたオブジェクトの変更も検知するららしい
なので、そのオブジェクトのみが存在するようなクエリを投げて、コレクションを取得すると、擬似的に「ネストしたオブジェクトの監視も出来るオブジェクト監視」ができる
らしい(実際やって確認取れてない)
https://stackoverflow.com/questions/46806476/realm-object-notifications-from-nested-objects
https://realm.io/jp/docs/swift/latest/#section-40
UITableViewControllerの入れ替えと、監視の反映がかぶって表示がバグる
UITableViewControllerのクソヤローが、入れ替えのときだけCellをかってに入れ替えてしまう(他の操作はこちらが自作しなければ何も起こらないというのに!)ので、入れ替えの操作からのモデルへの書き込みに
Realm.commitWrite(withoutNotifying:)
を使うしか無い。https://realm.io/jp/docs/swift/latest/#ui
ただそれだと、RealmObjectServer環境で別の端末が同期されたときにそっちだと何も起こらないので、まずい。
なので、すごい良くない実装だけど、監視のコールバックで「insertionsとdeletions」が1件ずつだった場合は入れ替えっぽいのでなにもしないという処理をいれる。
型変換(enumをStringで保存するときや、非オプショナルなプロパティを表現する時など)
一番きれいなのは、Realmをドメインオブジェクトとして使うという幻想をすてて、一段ラップすること。
それだと、あまりにRealmが悲しいので、多少汚いが
class Person: Object {
/* こうやって並べて書いておけば、_genderという物理プロパティはgenderという仮想プロパティを通して扱うし、オプショナルなのはRealmの都合なだけで、実質必須とするし、Gender以外の値は入れちゃダメというのがパット見表現できている */
var gender: Gender {
get {
return Gender(rawValue: _gender!)!
}
set {
_gender = newValue.rawValue
}
}
@objc dynamic var _gender: String? // private西体がRealmの都合上できない。しかし、_始まりのプロパティに気軽にアクセスするやつは流石にいないとおもう
}
RealmObjectServerの複数端末からの書き込みの排他制御
前提として、RealmのTransacitonはローカル環境の話であり、端末感のデータのSyncは後勝ちで無条件で上書きされる。
排他処理が必要な厳密な要件にRealmObjectServerなどを使わない
べきなのかもしれない。
最も簡単なのは、書き込む端末が一つだけになるように設計すること
あとは、書き込み処理は、別途サーバーを介して、サーバーtoRealmObjectServerで、常に直列的に行うようにするとか
あとは、以下のようにロック機構を実装する話になると思うが…
- ロック用のテーブルを作る(以下ロックテーブル
- 書き込みを行う端末(以下A
- Aはロックテーブルが空であることをチェック
- Aはロックテーブルに自身の情報のレコードをInsert
- Aはロックテーブルの情報をsync(同期的に)読み込む(この時点の最新の保証
- Aはロックテーブルの内容が自身のみであるかチェック。yesなら書き込み処理を行う
- Aは書き込み処理が終わったら、ロックテーブルから自身の情報を削除する
とかやるとデータ不整合は起きない気がする。
ただ、ちゃんと考えきれてない。
問題点
- 2~5の間でAが死んだら永久にロックが解けないのをどうするんだ
- 4でnoだった場合、リトライはどうするのか、リトライの衝突はどうするのか(ランダム秒待たせるのか)
継承したObjectの親クラスで検索したい
無理。
無理やりやるためには、言語的な継承ではなく、オブジェクトの包含関係で継承を表現する
class 動物: Object {
@objc dynamic var name: String?
convenience init(name: String?) {
self.init()
self.name = name
}
}
class 人間: Object {
@objc dynamic var 国籍: String?
@objc dynamic var super動物: 動物?
var name: String? {
get { return super動物.name }
set { super動物.name = newValue }
}
convenience init(国籍: String?, name: String?) {
self.init()
self.super動物 = 動物(name: name)
self.国籍 = 国籍
}
}
// 後はプロジェクト規約でconvenience_init以外使うなと言う
let 動物List = Realm().object(動物.self)
let 人間List = Realm().object(人間.self)