LoginSignup
59
59

More than 5 years have passed since last update.

Realm × Swift2 でidでデータを管理する

Last updated at Posted at 2015-11-04

目的

前回の記事: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も変更される。

完成品

これまでのことを含めてできたコードを以下に示す。

User.swift
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()
        }
    }
}


ViewController.swift
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 でシームレスに画像を保存する

59
59
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
59