【SwiftUI】Realmのマイグレーション方法!Migration is required due to the following errorsの解決法

この記事からわかること
- Swift UIでRealm Swiftの
操作 方法 - Migration is required due to the following errorsの解決法
- 既存のデータベース定義を変更する際の注意点
- SchemaVersionとは?
- Configurationとは?
- migrationBlockとは?
- プロパティを追加/削除/プロパティ名の変更/結合した場合のmigration
index
[open]
\ アプリをリリースしました /
環境
- Xcode:16.0
- iOS:18.0
- Swift:5.9
- R.Swift:7.8.0
- macOS:Sonoma 14.6.1
モバイル向けのデータベースを提供しているRealm Swiftの扱いの中でマイグレーションの方法をまとめていきます。
エラー:Migration is required due to the following errors
元々運用していたRealmのテーブル定義を途中でプロパティを追加したり、プライマリーキーを後から追加したいことがあると思います。
するとアプリ実行させると以下のようなエラーを吐いてアプリが停止してしまいます。
これは既に保存されているテーブル情報と新規で操作しようとしているテーブル情報が一致しないために起きてしまいます。これを解決する手段としてRealm Swiftでは「マイグレーション」と呼ばれる機能が用意されています。
ちなみに既存のデータベースデータを削除してしまえばエラーは発生しなくなりますが、ユーザーが溜めたデータをバージョンアップ(テーブル定義の変更)のたびにリセットされたらたまったもんじゃないですもんね。。
マイグレーションとは?
マイグレーションとは日本語で「移行」の意味をもつ英単語です。Realmではデータの整合性を保つためにあらかじめ変更点を定義して設定に組み込んでおくことで整合性を保ってくれる機能のことを指します。
マイグレーションのポイント
- SchemaVersion
- Configuration
上記のポイントは後述するのでまずはコードを見てみます。エラーを発生させないためにはRealm構造体をインスタンス化する前に下記の#1と#2のコードを実行させることです。
ageプロパティを追加した場合
SchemaVersion
Realmではmigrationの回数(version)を自分で管理する必要があります。初めてデータ変更した際は0になっているので値に1を指定します。
これは変更するたびに自分でインクリメントしていくので、再度プロパティを追加した場合は先ほどのコードのschemaVersion: 2
に変更する必要があります。変更しないと同様のエラーが発生してしまいます。
データ型はUInt64
型となっているのでマイナス値(-4)と小数点(1.4)などは指定できません。
Configuration
インクリメントしていくschemaVersionはRealm
構造体のConfiguration
構造体の引数に渡して使用します。
何やら色々引数に指定できる項目がありますが、重要なのはschemaVersion
とmigrationBlock
です。
schemaVersion
マイグレーションのバージョン番号をインクリメントしながら渡します。
migrationBlock
引数migrationBlock
には古いデータから新しいデータへと移行するために必要な処理を記述します。
プロパティを追加または削除やプライマリーキーを付与したい場合は必要ありませんが、プロパティ名を変更したり値同士を結合したりする場合は明示的にここに変更を記述する必要があります。
MigrationBlock型
MigrationBlock
型はタイプエイリアスなのでコードにすると以下のようになります。oldSchemaVersion
にはインクリメント前のバージョン数が格納されるのでここで中の処理を実行させるための分岐処理を行います。
マイグレーションのパターン
ここからは以下のテーブルクラス定義で既に運用していると仮定してマイグレーションを実装してみます。
プロパティの追加
プロパティを追加する場合はschemaVersion
をインクリメントするだけでOKです。
プロパティの削除
プロパティを削除する場合もschemaVersion
をインクリメントするだけでOKです。
プロパティ名を変更
プロパティ名を変更したい場合はschemaVersion
をインクリメントして、migrationBlock
の中で処理を記述していきます。
renameProperty
メソッドを呼び出しonType
にはクラス.className()
を、from
には旧プロパティ名をto
には新しいプロパティ名を渡します。
プロパティの値を連結させる
プロパティの値を連結させた新しいプロパティを追加したい場合はschemaVersion
をインクリメントして、migrationBlock
の中で処理を記述していきます。
enumerateObjects
メソッドを呼び出すと引数から古いバージョンのオブジェクトと新しいバージョンのオブジェクトに参照できるようになります。
プライマリーキーを付与する
プライマリーキーを付与する場合はschemaVersion
をインクリメントするだけでOKです。
しかしもし既にプライマリーキーに設定したプロパティに重複値が格納されていた場合以下のようなエラーを吐いてアプリが停止してしまいます。
この場合は既に格納済みの重複値を取り除くしか方法はないのでデータを丸々削除するか、重複したレコードを除去する必要があります。
Realmを操作するModelを使用している場合
MVVMアーキテクチャなどに準じたアプリ設計を行なっている場合はRealmのデータベース操作をModelなどにまとめることが多いと思います。
その場合は以下のようにクラスのプロパティにRealmインスタンスを保持させ、CRUD処理をメソッドとして用意すると思います。
上記のようなクラスを定義している場合にマイグレーションするにはプロパティへのRealmインスタンス格納を初期値ではなくイニシャライザを介することで実行することができるようになります。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。
私がSwift UI学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。