プログラマでありたい

おっさんになっても、プログラマでありつづけたい

リリース済みのiPhone/iPadアプリのDBの変更の仕方 或いはCoreDataを使ってスキーマの自動マイグレーション

 リリース済みのiPhone/iPadアプリのDBのテーブル定義を変更したい。こんなことって、ありますよね?しかし、サーバサイドのアプリと違って、クライアントサイドで動くiPhone/iPadアプリはどうやってデータの移行をすれば良いのでしょうか?リリース後に気がついて、私は小一時間途方にくれました。
 でも、iPhoneなら出来るんです。簡単に!!
正確に言うとApple謹製のDBのフレームワーク、CoreDataを使っていた場合は簡単に移行(マイグレーション)が実現出来ます。


詳しい情報は、次のリンクをご参照ください。
Core Data Model Versioning and Data Migration
Lightweight Migration


 簡単な手順としては、次のような形になります。

  • 新しいバージョンのモデルを追加する。

  Editor -> Add Model Version
  

  • 追加したモデルに、属性(カラム)を追加する。

  必要なだけ、追加します。

  • マッピングファイルを作成する。

  File -> New File -> Core Data -> Mapping Model
  マッピングファイルは、Source Data Model(移行元)とTarget Data Model(移行先)を指定します。
  注意点としては、どのバージョンからどのバージョンに移行するのかする解るようにすることです。
  どういうことかというと、Version1 -> Version2 -> Version3とこちらの期待通りに移行してくれるとは
  限らないということです。 Version1 -> Version3といった人もいます。
  なので、Version3まである場合は、 ver1->ver3とver2->ver3と2ファイルの用意が必要です。
  ファイル名もV1toV2.xcmappingmodel等、一目でわかる形が良いのではないでしょうか?
  

  • 自動マイグレーションコードを追加する。

  詳細は、下の方に書いておきます。

  • 現在のバージョンを変更する

  該当の.xcdatamodeldを選択して、File InspecterのVersioned Core Data ModelのCurrentを変更します。

自動マイグレーションのコード記述

 自動マイグレーションで、変換(マイグレーション)が起きるタイミングは、NSpersistentCoordinatorでオプションで変換を付けた時になります。データアクセスクラスみたいなので一元化しておけば、そこの部分にオプション追加するだけで対応が可能になります。
 私の場合は、DataManagerという基底クラスを作って、そこで 永続ストアコーディネータの作成やDBファイルの作成を一手に行なっているので、ここだけの修正で済みました。CoreDataを使った開発の詳細は、こちらのエントリーで書いています。
DataManager.m

NSError *error = nil;
NSURL *storeURL = <#The URL of a persistent store#>;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
 
BOOL success = [psc addPersistentStoreWithType:<#Store type#>
                    configuration:<#Configuration or nil#> URL:storeURL
                    options:options error:&error];
if (!success) {
    // Handle the error.
}

 ただ大量データの変換が必要な場合、注意が必要となります。数十件程度のデータであれば、すぐに終わります。が、それが数千件レベルのデータとなりますと、それ相応の時間が必要となります。その場合にアプリ起動時にいきなりマイグレーションが起こると、アプリの起動タイムアウトが発生する可能性があります。またそうではなくても、ユーザは壊れたかと思って中断することも考えられます。その点を考慮した上で、マイグレーションをどこで行うかの設計が必要になります。


 最初にiPhoneアプリでDB(SQLite)を使う時に、CoreDataを使うかサードパーティのFMDBを使うか悩みました。FMDBは慣れ親しんだSQL文で操作出来るし、記述量も少なめとかなり魅力的にみえました。一方、Appleのフレームワークの上という所でバージョンアップ時の対応等で継続性の懸念がありました。悩んだ末に、一度はちゃんとCoreDataを使ってみないとダメだろうと思い、CoreDataを採用した経緯があります。今となっては、良かったなぁと思います。正直、開発している段階ではここまで気が回らなかったので、助かりました。これから開発される方は、是非CoreDataをお使いください。


 あと、iPhone/iPadアプリを効率的にかつ保守性の高いコードで書くには、是非、木下さんのiOS開発におけるパターンによるオートマティズムをお読みください。CoreDataのサンプルコード等も入手出来て、本当に参考になります。


enjoy!!