#目次
SwiftでRealmを使う時のTips まえがき
SwiftでRealmを使う時のTips(1) アクセサとエンティティ編
SwiftでRealmを使う時のTips(2) 生成とオートインクリメント編
SwiftでRealmを使う時のTips(3) NSPredicate編
#似非オートインクリメント
Realm
にはオートインクリメント機能みたいなものはありません
整数型のIDを主キーにしてオブジェクトを扱うと色々と便利なので
「似非オートインクリメント」を前回に作ったアクセサクラスに追加します
public extension NBRealmAccessor {
/// オートインクリメントされたID値
public var autoIncrementedID: Int64 {
guard let max = self.realm.objects(Entity).sorted(NBRealmEntity.IDKey, ascending: false).first else {
return 1
}
return max.id + 1
}
}
「似非」と呼んでいるのは
正しくは今あるエンティティの中で最も大きいIDに1を足したものを返している・・・からです
厳密に言うとスキーマなどで管理されているオートインクリメントではありません
しかしアプリでデータベースを扱う上で、この方法で支障が出ることはなかなかないです
厳密さが必要な場合は、要件に応じてここを作り変えればいいわけです
この計算プロパティを使ってエンティティを作成するメソッドを追加しました
public extension NBRealmAccessor {
public func create() -> Entity {
let ret = Entity()
ret.id = self.autoIncrementedID
return ret
}
}
これでアクセサからエンティティを生成するときは
このように書くことが出来るようになりました
// 型推論により ": UserEntity" は不要ですが、わかりやすいように書いています
let user: UserEntity = UserAccessor().create()
しかし、この方法は問題が発生しました
下記のような場合の時です
for i in 0..<100 {
let user: UserEntity = UserAccessor().create()
}
create()
内の autoIncrementedID
プロパティが
毎回データベースを見に行ってIDの最大値を取得しに行くので
これがオーバヘッドを生み出しました
さらに、データベースに未だ保存していない状態で次の新しいエンティティを作ろうとすると
当たり前ですが、変数user
の id
は常に同じ値になります
なので、下記のように改修を行いました
public extension NBRealmAccessor {
public func create(withID id: Int64? = nil) -> Entity {
let ret = Entity()
ret.id = id ?? self.autoIncrementedID
return ret
}
}
IDを指定することによって、データベースへのアクセスが走らないようにしました
ループ時は下記のように書くことでオーバヘッドは極端に減ります
let accessor = UserAccessor()
var id = accessor.autoIncrementedID
for i in 0..<100 {
let user: UserEntity = accessor.create(withID: id)
id += 1
}
オーバロードメソッドになったので
最初に書いた方法を崩すこともありませんね
let user: UserEntity = UserAccessor().create()