Swift
Realm
Swift3.0

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