2018年3月1日木曜日

SwiftRealm で update 処理

概要

前回、基本的な操作方法を紹介しました
今回は更新系の処理を試してみました

環境

  • macOS 10.13.3
  • Xcode 9.2 (9C40b)
  • RealmSwift 3.1.1

クラス定義

まずはクラスを定義しましょう
シンプルに id 属性と name 属性を持つクラスを定義します

import RealmSwift

class User: Object {
    @objc dynamic var id = 0
    @objc dynamic var name: String? = nil

    override static func primaryKey() -> String? {
        return "id"
    }

    static func insertTestData() {
        let names = ["bob", "tom", "jessie"]
        var users: [User] = []
        for (id, name) in names.enumerated() {
            let user: User = User()
            user.name = name
            user.id = id
            users.append(user)
        }
        let realm = try! Realm()
        try! realm.write {
            realm.add(users)
        }
    }

    static func debug() {
        let realm = try! Realm()
        let user = realm.objects(User.self)
        for u in user {
            print(u.id)
            print(u.name!)
        }
    }
}

そしていきなりポイントですが id 属性を Primary Key として登録しています
更新系の処理を行う場合はこの定義がないとエラーとなります

あとテストデータを挿入するためのメソッドと挿入したデータを表示するだけのメソッドを追加しています

一旦実行する

今回はシングルビューアプリケーションにしたので ViewController 側で定義したクラスを呼び出します

override func viewDidLoad() {
    super.viewDidLoad()
    User.insertTestData()
    User.debug()
}

実行結果は以下の通りです

0
bob
1
tom
2
jessie

更新するためのメソッドを追加する

先ほどの User クラスに以下のメソッドを追加しましょう

static func update(id: Int, name: String) {
    let realm = try! Realm()
    let user = User()
    user.id = id
    user.name = name
    try! realm.write {
        realm.add(user, update: true)
    }
}

id と name を指定して該当する id のレコードを更新します
ポイントは add を引数付きでコールする点で update: true を付与すると Primary Key で該当するレコードがあるとそのレコードを更新してくれます
実行してみましょう

override func viewDidLoad() {
    super.viewDidLoad()
    User.update(id: 0, name: "holly")
    User.debug()
}

新規でレコードを追加せず指定した id のレコードが更新されているのがわかります

0
holly
1
tom
2
jessie

該当する id がない場合の挙動

例えば今回の場合 User.update(id: 3, name: "holly") という感じでコールすると以下のようになりました

0
holly
1
tom
2
jessie
3
holly

所謂 upsert の挙動になります
該当するレコードがある場合は更新し、ない場合は新規のレコードとして追加します

ちなみに update: false にして同じように id = 3 のユーザを登録しようとするとプライマリキーが重複しているよーというエラーになります

Terminating app due to uncaught exception 'RLMException', reason: 'Attempting to create an object of type 'User' with an existing primary key value '3'.'

該当するレコードがない場合に追加しないようにするには

それ専用のメソッドがないようなので条件に合うレコードがある場合は更新してない場合は何もしないというメソッドを定義します

static func updateOnly(id: Int, name: String) {
    let realm = try! Realm()
    let user = realm.objects(User.self).filter("id == \(id)")
    if !user.isEmpty {
        try! realm.write {
            user[0].name = name
        }
    }
 }

あとは以下のような感じでコールすれば id = 10 の場合にエラーとならずかつ新規で追加もされません

override func viewDidLoad() {
    super.viewDidLoad()
    User.updateOnly(id: 3, name: "jobs")
    User.updateOnly(id: 10, name: "none")
    User.debug()
}

最後に

RealmSwift で update 処理を試してみました
ポイントは Primary Key を定義する点かなと思います

0 件のコメント:

コメントを投稿