はじめに
Realm
にはauto increment
の機構がありません。
なので、僕なりに工夫したことを残しておきます。
なお、本コードはスレッドセーフで使うことを前提としています。
もし、非同期で同時のタイミングで保存する可能性がある場合はsynchronized
などの処理を施してください。
コード
何はともあれコードは以下になります。
class RObject: Object {
// ID
dynamic var id = 0
// データを保存。
func save() {
let realm = try! Realm()
if realm.isInWriteTransaction {
if self.id == 0 { self.id = self.createNewId() }
realm.add(self, update: true)
} else {
try! realm.write {
if self.id == 0 { self.id = self.createNewId() }
realm.add(self, update: true)
}
}
}
// 新しいIDを採番します。
private func createNewId() -> Int {
let realm = try! Realm()
return (realm.objects(type(of: self).self).sorted(byKeyPath: "id", ascending: false).first?.id ?? 0) + 1
}
// プライマリーキーの設定
override static func primaryKey() -> String? {
return "id"
}
}
使い方
Modelオブジェクトを以下のように定義します。
class User: RObject {
// 名前
dynamic var name = ""
}
上記のクラスを保存する場合
let user = User()
user.name = "hoge"
user.save()
更新もしくは新規登録する場合
let realm = try! Realm()
let user = realm.objects(User.self).first ?? User()
try! realm.write {
user.name = "hoge"
user.save()
}
最後に
この方法を使えば全てのオブジェクトにid
が自動的に付与されるのでRails
のように使えます。(言い過ぎ
注意点として、現在のバージョン(2.5.0)の時点では親子関係があってもキャストができないので注意。
(RObject
にキャストすることはないと思いますが、、、念のため)