目的
前回の記事:Realm × Swift2 でデータを保存してみるの続き。
primaryKeyとしてidを用いて、RealmのDB(データベース)を作成すること
autoIncrement(に見える実装)を目指す。
続き → Realm × Swift2 でシームレスに画像を保存する
primaryKey
Realmでは、primaryKeyとして特定のプロパティを指定することができる。今回はidを用いる。
primaryKeyは以下に示すstaticメソッドをoverrideして、文字列としてプロパティ名を返すことによって実現できる。
dynamic private var id = 0
override static func primaryKey() -> String? {
return "id"
}
もちろんidもDBに保存され、これをプライマリキーとして、操作を行うことができる。
primaryKeyによるupdate
primaryKeyは重複を許さない。すなわち、今まで使っていたメソッド
realm.add (object)
では、もし同じidを持った別のオブジェクトがaddに渡された時には、例外が発生してしまう。
そこで、別のメソッド、
User.realm.add (object: Object, update: Bool)
のupdateをtrueにして呼び出すと、idが重複した時は上書きをすることができる。
今回はidを自動生成しているが、間違えて自分でinitしてしまった時に、大切なデータを消してしまわないように、add(object)のままにしておく。
autoIncrement
static func lastId() -> Int {
if let user = realm.objects(User).last {
return user.id + 1
} else {
return 1
}
}
そう、見ての通り、一度読みだした後、一番後ろのidを加算してreturnしている。
Realmは仕組み上、値を読みだした後利用して初めてメモリに値がセットされるので、realm.objects(User).lastと書いても、objects(User)の結果が全てメモリにロードされるようなことはない。
一度ロードした後は、lastIdを持っておいてもいいかもしれませんね。
プロパティのupdate
アップデート処理は、トランザクションの中で行う。
すなわち、
let users = User.loadAll()
print(users)
for user in users {
try! User.realm.write {
user.name = "全部はるふ"
}
}
print(User.loadAll())
のようにする。
たとえaというインスタンスを保存したとしても、一度保存すると変換されてしまうので、updateするにはトランザクションの中で行う必要がある。
トランザクションの中で行うと、自動的にDBも変更される。
完成品
これまでのことを含めてできたコードを以下に示す。
import RealmSwift
class User: Object {
static let realm = try! Realm()
dynamic private var id = 0
dynamic var name = ""
override static func primaryKey() -> String? {
return "id"
}
static func create() -> User {
let user = User()
user.id = lastId()
return user
}
static func loadAll() -> [User] {
let users = realm.objects(User).sorted("id", ascending: false)
var ret: [User] = []
for user in users {
ret.append(user)
}
return ret
}
static func lastId() -> Int {
if let user = realm.objects(User).last {
return user.id + 1
} else {
return 1
}
}
// addのみ
func save() {
try! User.realm.write {
User.realm.add(self)
}
}
func update(method: (() -> Void)) {
try! User.realm.write {
method()
}
}
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a = User.create()
a.name = "はるふ"
a.save()
let b = User.create()
b.name = "はるふす300"
b.save()
let users = User.loadAll()
print(users)
// 全てのnameを変更してしまう
for user in users {
user.update {
user.name = "全部はるふ"
}
}
// 再度loadして表示(loadし直す必要はないが・・・)
print(User.loadAll())
}
}
ViewControllerからはidを意識することなく、実装されている。
エラーハンドリングは、今回もまた、何もしてない。。。
続き
1つめの記事 → Realm × Swift2 でデータを保存してみる
2つめの記事 → Realm × Swift2 でidでデータを管理する(この記事)
3つめの記事 → Realm × Swift2 でシームレスに画像を保存する