スレッド間のオブジェクト共有不可能
一意に検索できるものを渡して別スレッド上で再検索し、オブジェクトを生成する。
let realm = try! Realm()
let foo1 = realm.objects(Foo).first!
let fooId = foo1.id
let q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(q) {
let foo2 = realm.objects(Foo).filter("id = %@", fooId).first!
print(foo2.name) // ok
print(foo1.name) // error
}
オブジェクトを削除すると関連している箇所はnilになる
class Foo: Object {
dynamic var id = NSUUID().UUIDString
dynamic var bar: Bar?
let bazList = List<Baz>()
}
class Bar: Object {
dynamic var id = NSUUID().UUIDString
}
class Baz: Object {
dynamic var id = NSUUID().UUIDString
}
let realm = try! Realm()
let bar = Bar()
let baz = Baz()
let foo = Foo(value: ["bar": bar, "baz": baz])
realm.write {
realm.add(bar)
realm.add(baz)
realm.add(foo)
realm.delete(bar)
realm.delete(baz)
}
print(foo.bar) // nil
print(foo.bazList.count) // 0
Realm#delete()はSequenceTypeなものは入る
Realm Docsのオブジェクトの削除にはオブジェクト単体かDB内全削除しか例にないが、 delete() の定義を見ると
public func delete<S: SequenceType where S.Generator.Element: Object>(objects: S)
があるので、次のように同時に複数のオブジェクトを削除することもできる。
// 検索結果を利用して削除
realm.delete(realm.objects(Foo).filter("id IN %@", ["a", "b"]))
// 関連しているオブジェクトを削除
realm.delete(foo.bazList)
LinkingObjectsは遅延解決
Realmにおけるオブジェクト間の関係は一方向なので、本来は両方に別オブジェクトへの関係を書かないといけないのだが、大きくなればなるほど整合性を保つのが大変になる。
そのために存在するのが LinkingObjects である。
class Foo: Object {
dynamic var name = ""
dynamic var bar: Bar?
}
class Bar: Object {
dynamic var name = ""
let fooList = LinkingObjects(fromType: Foo.self, property: "bar")
}
ただし、LinkingObjectsはリストのようなものなので、OneToOneのような関係の場合は次のように書いてしまいがち。
class Bar: Object {
let foo = LinkingObjects(fromType: Foo.self, property: "bar").first!
}
これは必ずnilになる。
なぜかというと、LinkingObjectsはオブジェクトが生成されてから意味を持つオブジェクトなので、それまでは何のデータもないオブジェクトになるから。
もし単体で欲しい場合は、次のように書く必要がある。
public class Bar: Object {
private let fooList = LinkingObjects(fromType: Foo.self, property: "bar")
public var foo: Foo { return fooList.first! }
}
データモデルへの変更はリアルタイム
Realmの更新は全てトランザクション内でないといけないので
let foo = realm.objects(Foo.self).first!
foo.name = "foo"
try! realm.write { realm.add(foo, update: true) }
とかやろうとするとfoo.name = "foo"
の時点でエラーになるので、次のようにトランザクション内で全て行う必要がある。
let foo = realm.objects(Foo.self).first!
try! realm.write {
foo.name = "foo"
}
結局Realmオブジェクトを剥き出しにしないとならなくなるので、何かのクラス内に押し込めたく考えた結果、次のような方法で更新処理をするようにした。
let foo = Foo(value: realm.objects(Foo.self).first!)
foo.name = "foo"
try! realm.write { realm.add(foo, update: true) }
Fooにはちゃんとプライマリーキーを設定しないといけない。