Posted at

RealmのIDを自動採番(オートインクリメント)する方法

More than 1 year has passed since last update.


はじめに

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にキャストすることはないと思いますが、、、念のため)