【RealmSwift】マイグレーション処理をする

これをせずに、モデル変更 → エラーかます → ググる を繰り返してるので、覚えるためにもまとめます。w

マイグレーションとは

モデル定義が変わったときに、既存データを新規データの仕様に移行することです。
公式ドキュメントの例を少し拝借すると、例えば、以下のようなユーザー情報を保持するモデルクラスがあるとします。

//----- Ver1.0.0 -----//

class User: Object {
    @objc dynamic var uniqueId = ""
    @objc dynamic var firstName = ""
    @objc dynamic var lastName = ""
    @objc dynamic var age = 0

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

次のアップデートで「名前を1つに統一する」仕様になったとします。
そうすると、

//----- Ver1.0.1(姓名を統一する場合) -----//

class User: Object {
    @objc dynamic var uniqueId = ""
    @objc dynamic var fullName = ""
    @objc dynamic var age = 0

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

こんな感じになります。
この fullName は、firstName + lastName となり、既存データ(Ver1.0.0)を新規データ(Ver1.0.1)の仕様に移行する必要があるので、マイグレーションが必要になります!

ちなみに、この「マイグレーション」という用語自体は Apple や Realm 特有のものではなく、一般的なデータベース用語です。
データベースとか特に詳しくなかったので、最初は特有のものと思ってました( ゚д゚ )

実装

先ほどのユーザーを例に実装していきます。
マイグレーションは結構簡単で、AppDelegate に以下のようなコードを挿入したら完了です。

【2020年7月20日】最新コードを掲載。

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions: launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        var config = Realm.Configuration()
        config.migrationBlock = { migration, oldSchemaVersion in
            // 設定していなければ oldSchemaVersion はゼロがデフォルトです
            if oldSchemaVersion < 1 {
                // 保存されている User 全てを列挙
                migration.enumerateObjects(ofType: User.className()) { (oldObject, newObject) in
                    let firstName = oldObject!["firstName"] as! String
                    let lastName = oldObject!["lastName"] as! String
                    newObject!["fullName"] = firstName + lastName
                }
            }
        }
        // 現在のRealmファイルの schemaVersion と、下記で設定した schemaVersion が違うと、マイグレーションが実行される
        config.schemaVersion = 1
        Realm.Configuration.defaultConfiguration = config

        return true

}

基本的にやってることは変わりませんが、すっきりした印象です。
以前のコードも残しておきます!

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions: launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { migration, oldSchemaVersion in
            if (oldSchemaVersion < 1) {
                migration.enumerateObjects(ofType: User.className()) { oldObject, newObject in
                    let firstName = oldObject!["firstName"] as! String
                    let lastName = oldObject!["lastName"] as! String
                    newObject!["fullName"] = firstName + lastName
                }
            }
        })
        Realm.Configuration.defaultConfiguration = config

        return true
    }

}

データ構造を変えるたびに、schemaVersion をインクリメントしていけば大丈夫です。

注意する点

このマイグレーション処理で気をつけたいのが、アプリのアップデートを飛ばすユーザーもいるということです。
Ver1.0.0 をインストールしているユーザーが、Ver1.0.1 を飛ばして Ver1.0.2 にアップデートするかもしれません。
なので、マイグレーション処理はネストせず、比較も「 < 」で行うことです。

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions: launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        var config = Realm.Configuration()
        config.migrationBlock = { migration, oldSchemaVersion in
             if oldSchemaVersion < 1 {
                migration.enumerateObjects(ofType: User.className()) { (oldObject, newObject) in
                    let firstName = oldObject!["firstName"] as! String
                    let lastName = oldObject!["lastName"] as! String
                    newObject!["fullName"] = firstName + lastName
                }
            }
            if oldSchemaVersion < 2 {
                // ここで次のマイグレーションを記載する
            }
        })
        config.schemaVersion = 1
        Realm.Configuration.defaultConfiguration = config

        return true
    }

}

ここ失敗するとユーザーが離れる事態になりかねないので、慎重に作業していきましょう (·ω·`*)


違うよ!とかこういう方法あるよ!ってのがあれば教えてください。
では( ¯·ω·¯ )

Realm
スポンサーリンク

コメント