これをせずに、モデル変更 → エラーかます → ググる を繰り返してるので、覚えるためにもまとめます。w
マイグレーションとは
モデル定義が変わったときに、既存データを新規データの仕様に移行することです。
公式ドキュメントの例を少し拝借すると、例えば、以下のようなユーザー情報を保持するモデルクラスがあるとします。
1 2 3 4 5 6 7 8 9 10 11 12 |
//----- 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つに統一する」仕様になったとします。
そうすると、
1 2 3 4 5 6 7 8 9 10 11 |
//----- 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日】最新コードを掲載。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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 } |
基本的にやってることは変わりませんが、すっきりした印象です。
以前のコードも残しておきます!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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 にアップデートするかもしれません。
なので、マイグレーション処理はネストせず、比較も「 < 」で行うことです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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 } } |
ここ失敗するとユーザーが離れる事態になりかねないので、慎重に作業していきましょう (·ω·`*)
br>
br>
違うよ!とかこういう方法あるよ!ってのがあれば教えてください。
では( ¯·ω·¯ )
コメント