iPhone Appのサンプルコード SQLiteBooksのソースを読む -1-

AppDelegateのapplicationDidFinishLaunchingメソッド

デベロッパドキュメントを見ると、applicationDidFinishLaunchingメソッドは
アプリケーションの初期化や設定を行うメソッドのようだ。
アプリケーションを起動して確認すると、アプリケーション起動後にこのメソッドが呼ばれていた。

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // The application ships with a default database in its bundle. If anything in the application
    // bundle is altered, the code sign will fail. We want the database to be editable by users, 
    // so we need to create a copy of it in the application's Documents directory.     
    [self createEditableCopyOfDatabaseIfNeeded];
    // Call internal method to initialize database connection
    [self initializeDatabase];
    // Add the navigation controller's view to the window
    [window addSubview:navigationController.view];
    [window makeKeyAndVisible];
}


下記の行ではどのような処理が行われているのか,それぞれのメソッドを確認してみる。

    [self createEditableCopyOfDatabaseIfNeeded];

    [self initializeDatabase];

AppDelegateのcreateEditableCopyOfDatabaseIfNeededメソッド

このメソッドはざっと見た感じだと、bookdb.sqlをdefaultDBPathからwritableDBPathにコピーしているようだ。

- (void)createEditableCopyOfDatabaseIfNeeded {
    // First, test for existence.
    BOOL success;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"bookdb.sql"];
    success = [fileManager fileExistsAtPath:writableDBPath];
    if (success) return;
    // The writable database does not exist, so copy the default to the appropriate location.
    NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"bookdb.sql"];
    success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
    if (!success) {
        NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
    }
}

下記のようのデバッグ文を追加し動きを見てみる

- (void)createEditableCopyOfDatabaseIfNeeded {
	NSLog(@"AppDelegate#createEditableCopyOfDatabaseIfNeeded");	// デバッグ文

    // First, test for existence.
    BOOL success;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"bookdb.sql"];
	NSLog(@"writableDBPath : %@",writableDBPath);	// デバッグ文
    success = [fileManager fileExistsAtPath:writableDBPath];
    if (success) return;
    // The writable database does not exist, so copy the default to the appropriate location.
    NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"bookdb.sql"];
	
	NSLog(@"defaultDBPath : %@",defaultDBPath);	// デバッグ文

    success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
    if (!success) {
        NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
    }
}

デバッガコンソールの出力

2008-11-30 03:48:44.791 SQLiteBooks[23873:20b] AppDelegate#createEditableCopyOfDatabaseIfNeeded
2008-11-30 03:48:44.792 SQLiteBooks[23873:20b] writableDBPath : /Users/kuru/Library/Application Support/iPhone Simulator/User/Applications/1AA2BAC3-02D1-4042-A9BC-07AB15603F94/Documents/bookdb.sql
2008-11-30 03:48:44.792 SQLiteBooks[23873:20b] defaultDBPath : /Users/kuru/Library/Application Support/iPhone Simulator/User/Applications/1AA2BAC3-02D1-4042-A9BC-07AB15603F94/SQLiteBooks.app/bookdb.sql


Coding How-To’s (iPhoneCodingHowTo-J.pdf)の14ページの「アプリケーションにSQLiteデータベースをバンドルするには?」に下記のような記述がある。

SQLiteデータベースに書き込む必要がある場合は、アプリケーションの起動時に、
書類など、アプリケーションのサンドボッ クスにあるディレクトリの1つにコピーする必要があります。

ここでは、この処理を行っているのか?



このファイルのコピー処理は、下記の行でファイルが存在したらコピー処理を行わないようになっているので
アプリケーションの初回起動時のみにコピー処理が実行されている。

    success = [fileManager fileExistsAtPath:writableDBPath];
    if (success) return;

アプリケーションのディレクトリ構造

アプリケーションのディレクトリ構造については、
iPhone OSプログラミングガイド(iPhoneOSProgrammingGuide.pdf)のP79に下記のように記載されている。

/AppName.app

これはアプリケーション自体を含む、バンドルの ディレクトリです。
アプリケーションは署名され ている必要があるため、
実行時にこのディレクト リの内容を変更してはなりません。
変更を加える と、後でアプリケーションを起動できなくなりま す。

/Documents/

アプリケーション固有のすべてのデータファイルを書き込むために使用するディレクトリです。

/Library/Preferences/

このディレクトリにはアプリケーションの環境設定ファイルが含まれます。
ディレクトリ内に、デベロッパ自身がファイルを作成してはいけません。
代わりに、NSUserDefaultsクラスまたはCFPreferences APIを使用してアプリケーションの環境設定にアクセスします。

/tmp/

これは一時ファイルを書き込むために使用するディレクトリです。
このディレクトリの内容のクリーンアップは、アプリケーションがしなければいけません。
自動的にクリーンアップする仕組みは用意されていません。



bookdb.sqlは何?

ここでコピーしているbookdb.sqlというファイルは何なのか?
SQLiteBooksプロジェクトには最初からbookdb.sqlというファイルが存在するが
これはどうやって作るのか?
ということで少し調べてみた。

データベースファイルの作成

SQLiteのデータベースファイルは、sqlite3コマンドで作成するらしい。
サンプルコードSQLiteBooksのbookdb.sqlも、sqlite3で作成されたものだろう。
SQLiteBooksのReadMe.txtをみると下記の記述がある。

Creating the Database File
The SQLite database file was created outside the application and then attached as resource file to be included in the application bundle. The database was created using the SQLite Command Line Interface (CLI). Although there are cases in which you may wish to create the database at run time, in many cases this is not necessary. To start the SQLite CLI, lauch Terminal.app and enter:

host:~ username$ sqlite3 my_database.sqlite

This will start the SQLite CLI and either open "my_database.sqlite" if it exists, or create it if it does not. Note that this is a path relative to your Terminal session's current directory.

After entering the above command, you should see something like the following:

SQLite version 3.4.0
Enter ".help" for instructions
sqlite> 

Now you can enter standard SQL language queries. The following queries were used to create the database in this sample:

CREATE TABLE book ('pk' INTEGER PRIMARY KEY, 'title' CHAR(32), 'copyright' REAL, 'author' CHAR(48));
INSERT INTO book(title, copyright, author) VALUES ('War and Peace', -3153600000, 'Leo Tolstoy');
INSERT INTO book(title, copyright, author) VALUES ('Mac OS X Internals', 1166832000, 'Amit Singh');
INSERT INTO book(title, copyright, author) VALUES ('The Divine Comedy', -20466864000, 'Dante Alighieri');

iPhone OSプログラミングガイド(iPhoneOSProgrammingGuide.pdf)の39ページにSQLiteのことが少し書いてあるが
「SQLiteの使用の詳細に ついては、http://www.sqlite.orgを参照してください。 」となっている。