ある日、Xcodeのデバッグバーにこんな表示がでた。
DB Error : 1 "no such table: テーブル名”
既にいくつかのテーブルがはいったデータベースを参照して実行しているはずが、テーブルが存在しないというエラーだ。
このエラーでググって、検索結果を片っ端から試したが、ことごとく失敗に終わってしまった。
何か重大な勘違いをしているのではないかと思ったので、アプリケーションのビルド時におけるデータベースの扱い方についてまとめる。
前提
- Mac用SQLiteクライアントLitaで作ったSelfPhoto.sqliteをマスターデータとして用意
- VSCardというプロジェクトを用意
- iOS で SQLite を簡単に扱うためのライブラリ、FMDBを利用
状況確認
まず、エラー時の状況をよく確認する。
アプリケーションをビルドした際、データベースSelfPhoto.sqliteの位置は当然ながらXcodeプロジェクト内ではなく、シミュレータもしくは実機の対象アプリケーション専用のサンドボックス(アプリケーション専用のディレクトリ)内で、Documentsディレクトリ以下に設置される。
場所は下記のとおり。
/Users/ユーザ名/Library/Application Support/iPhone Simulator/iOSのバージョン/Applications/アプリケーションのUUID/Documents
確認すると確かにSelfPhoto.sqliteが存在した。
しかし、これをLitaで開いてみると何もテーブルが存在していない。0 kbだ。
確かにXcodeにはマスターデータをドラッグアンドドロップしたはずなのに、何もはいっていない。
一体何がおこっているのか。
アプリケーションビルド時のデータベースの扱い
まず、iOSアプリケーションをビルドすると、Xcodeはアプリケーションをバンドルとしてパッケージ化する。
バンドル…関連のあるリソースをひとつの場所に集めた、ファイルシステム上のディレクトリ。iOSアプリケーションのバンドルには、アプリケーションの実行可能ファイルと支援用リソースファイル(アプリケーションアイコン、画像ファイル、ローカライズされたコンテンツなど)が含まれる。
データベースに関してはサンドボックス内のDocumentsディレクトリに設置される。
データベースをDocumentsディレクトリに設置する方法として、コード上で直接Documents以下にデータベースファイルを新規作成する処理を記述するか、先述のバンドル内からDocuments以下にコピーしてくる処理を記述しなければならないことが、いろいろ調べてみてわかった。
今回、マスターデータを利用するということで、コードで処理する前の準備として、バンドル内にマスターデータがはいったデータベースファイルを設置する必要があるようだ。
バンドル内へデータベースファイルを追加する方法は2つある。
1,データベースファイルをXcodeプロジェクト内に追加する際、下記のチェックをいれる。
2,データベースファイルをXcodeプロジェクト内に追加した後、TARGETSのCopy Bundle Resourcesにデータベースファイルを追加する
方法1の際にチェックを入れ忘れていたときに利用。
下記画面上で、Copy Bundle Resources欄で+をクリックして対象データベースを追加する。
もし、選択状態が解除されていることに気づかずに、そのままプロジェクトに追加してしまうと、プロジェクトには追加されるもののコンパイル対象には含まれないという状態になってしまう。
まとめ
今回のエラーの原因は
・コード上にデータベースをDocuments以下に新規作成する処理のみが記載され、テーブルを作成する処理が記載されていなかった。
このため、 空のデータベース(0 kb)が作成されただけで、何もテーブルが入っておらず、no such table…エラーが出た。
しかし、やりたかったことはマスターデータの入ったデータベースを反映させることなので、本質的な解決法は下記になる。
・マスターデータが入ったデータベースファイルをCopy Bundle Resourcesに設置し、コード上で、Documents以下にデータベースファイルの存在を確認後、存在しなければアプリケーションバンドルからコピーする処理を記述する。
データベースファイルを新規作成したり、コピーしたりするコード例は他のいろいろなサイトに記載されているので、ググッてみて欲しい。
以上。