RealmのschemaVersion

Realmのドキュメントのマイグレーション項目で言及されている通り、Realmを扱う際にはRealm.Configurationの引数であるschemaVersionにモデルにアップデートがあった際に以前のバージョンよりも大きい値を設定する必要があります。なお、この値はマイグレーションなどの処理を行う際に必要となり、Realm内部でoldSchemaVersion(初期値0)よりも最新のschemaVersionが大きいか否かで自動的にマイグレーションされます。(データ移行の際はmigrationBlockで移行処理を記述する)

schemaVersionをどのように管理すべきか

方法1. モデルのアップデートを行う際に手元でschemaVersionをインクリメントする

個人的にオススメしません。複数人で開発していた際に同時にアップデートすることもあるかと思います。その際にコンフリクトしたり、配信されているとschemaVersionが正しくインクリメントされておらずクラッシュも起きうると考えられます。

方法2. ビルド番号を直接入れる

アプリバージョンに関わらず、ビルド番号をGitのコミット数などでインクリメントしている場合、ビルド番号をschemaVersionに入れることも方法の1つかと思います。この場合だと実装者に関わらず常にインクリメントされていくのでschemaVersionも自動で上がってくれます。この方法がお手軽ですが、モデルにアップデートがないのにも関わらずインクリメントされるのは違和感に感じます。また、ビルド番号をどのように管理しているかにも依存するので開発方針に左右されます。

以上の方法を踏まえて実現したい理想

  1. schemaVersionはモデルのアップデートが行われた際のみインクリメントしたい。
  2. 複数人開発においても正しく管理されるようにGitに依存した値を注入したい

モデルのディレクトリ以下のgit logからschemaVersionを設定する

最終的にfastlaneのlaneとして定義できるようにします。

Step1. 特定のディレクトリ以下のマージコミットを取得する

git log --oneline --merges --first-parent master -- DIR_PATH | wc -l

上記のコマンドでDIR_PATH上の変更に対するマージコミットのカウントが取れます。
DIR_PATHはモデルが存在するディレクトリです。最終的にはこの数を最新のschemaVersionとして設定します。

Step2. 現在のブランチの最新マージコミット(コミットハッシュ)を取得する

git log --oneline --merges --pretty=format:"%h" -1

取得したコミットハッシュをHASH_STEP2とします。

Step3. 現在のブランチの最新コミット(コミットハッシュ)を取得する

git log --oneline --pretty=format:"%h" -1

取得したコミットハッシュをHASH_STEP3とします。

Step4. 最新のマージコミットと現在のコミット間で特定ディレクトリ上の変更のコミット数を取得する

git log --oneline HASH_STEP2..HASH_STEP3 -- DIR_PATH | wc -l

これによってDIR_PATHにおいて現在、変更を行ったかが0かどうかで判断することができます。

Step5. Step1~4を用いてlaneを組む

  lane :bump_schema_version do
    latest_merges_commit_hash = sh(%Q[git log --oneline --merges --pretty=format:"%h" -1])
    latest_commit_hash = sh(%Q[git log --oneline --pretty=format:"%h" -1])
    latest_model_commit_count = sh(%Q[git log --oneline #{latest_merges_commit_hash}..#{latest_commit_hash} -- DIR_PATH | wc -l]).strip!.to_i
    latest_schema_version = sh("git log --oneline --merges --first-parent master -- DIR_PATH | wc -l").strip!.to_i

    if latest_model_commit_count > 0 
      latest_schema_version += 1
    end

    set_info_plist_value(path: PLIST_PATH, key: "schemaVersion", value: latest_schema_version)
  end

set_info_plist_valueでInfo.plist内のschemaVersionに書き込み、コードから取得することでRealm.Configurationに渡すことができます。

このlaneを実行することで現在のブランチで変更があるかを取得することができます。

latest_schema_versionをmasterへのマージコミット数としているのはCI上で実行したときにはモデルのディレクトリにおける変更のmasterマージコミット数schemaVersionとするためです。
まだマージしていないブランチ上で実行したときにはStep4で行っている現在変更しているかを加味してlatest_schema_versionがインクリメントされます。

前者と後者の値は一致するので「手元で実行してPR作成によってインクリメントする」or「CI上でフックして実行、PR作成する」などインクリメントする方法を選択することができます。

最後に

schemaVersionの管理方法をどのようにするかはプロジェクトによっても変わりますし、悩ましい部分だと思います。
他の方法もあればぜひ教えてください!