[Swift]Realm Swift #3 トラブル対応


iOS でRealm Swift を 利用し、サンプルを作成する際のトラブル内容と対応事項をメモします。

目次

・ Realm Swift#1 class
・ Realm Swift#2 sample
・ Realm Swift#3 issue

動作環境

Swift 5.0
Xcode 11.1

トラブル一覧

1。レルムにデータ追加失敗の時
2。複数カラムのプライマリーキーが作成したい場合
3。 レルム取得する際にアプリクラッシュされる場合

レルムにデータ追加失敗の時

StudentAccessor.swift
class Student: Object {
    @objc dynamic var studentId = ""
    @objc dynamic var name = ""
    @objc dynamic var age = 0
}
func add(obj :T) throws {
    let realm = try! Realm()
    try realm.write {
        realm.add(obj, update: .modified)
    }
}

下記のようにRLMExceptionエラーが起きる。 


理由 : 主キーが存在しないため、更新できません。

対応方法

対応① 主キーを設定すること。

※注意:https://realm.io/docs/swift/3.20.0/#models
主キーを宣言すると、オブジェクトを効率的に検索および更新でき、
各値に一意性を適用できます。
主キーを持つオブジェクトをレルムに追加すると、
主キーは変更できなくなります。

StudentAccessor.swift(Primarykey)
override public static func primaryKey() -> String? {
    return "studentId"
}

対応②:主キーが設定できない場合

StudentAccessor.swift(追加のみ)
try realm.write {
    //追加の場合
    //realm.add(obj, update: .modified)
    realm.add(obj)
}
StudentAccessor.swift(更新のみ)
let student = realm.getObjects.first
try realm.write {
    //更新の場合
    student?.name = "test"
    student?.age = 20
}

複数カラムの主キーが作成したい場合

Student.swift(NG)
class Student: Object {
    @objc dynamic var studentId = ""
    @objc dynamic var age = 0

    override public static func primaryKey() -> String? {
        return String(format: "%@_%d ", studentId,age)
    }

(NG) 理由:主キーは一つ項目であるため、

対応: 主キー(customPrimaryKey)を新しく作成すること。

但し、不要な項目が追加されてしまう。

Student.swift(OK)
class Student: Object {
    @objc dynamic var studentId = ""
    @objc dynamic var age = 0
    @objc dynamic var customPrimaryKey = ""

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

    convenience init(studentId: String, age: Int) {
        self.init()
        self.studentId = studentId
        self.age = age
        self.customPrimaryKey =  String(format: "%@_%d ", studentId,age)
    }

レルム取得する際にアプリクラッシュされる場合

RealmBaseDao.swift(NG)
func updateOnly(block:() -> Void ) throws {
    try realm.write(block)
}

原因 : 想定ですが、クロージャは解放されず、
レルムのトランザクションを完了されなっかた。

対応: @ escapingを付与すること。

・クロージャが外部から渡される場合、@ escapingが必須らしい。
・非同期処理の後にクロージャを実行する場合は、
@ escaping を引数で受け取るクロージャに付与しなければなりません。

RealmBaseDao.swift(OK)
func updateOnly(block: @escaping () -> Void ) throws {
    try realm.write(block)
}

参考

https://realm.io/docs/swift/3.20.0/
@escapingと@autoclosure

Index

≪ Realm Swift #2 サンプル