iPhone Appのサンプルコード SQLiteBooksのソースを読む - 2.アプリケーション起動時のDB読み込み

アプリケーション起動時にDBからデータを読み込んでいる部分のソースを確認する。

AppDelegateのinitializeDatabaseメソッド

applicationDidFinishLaunchingメソッドの中から呼ばれているinitializeDatabaseメソッドは何をやっているのか?
DB(bookdb.sql)に接続し、取得したデータをself.booksに格納しているようだ。
アプリケーションの起動時にbooksにデータを読み込み、MasterViewControllerでbooksからデータを取得し画面に表示しているようだ。

AppDelegate.m
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
    NSMutableArray *bookArray = [[NSMutableArray alloc] init];
    self.books = bookArray;
    [bookArray release];
    // The database is stored in the application bundle. 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"bookdb.sql"];
    // Open the database. The database was prepared outside the application.
    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
        // Get the primary key for all books.
        const char *sql = "SELECT pk FROM book";
        sqlite3_stmt *statement;
        // Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
        // The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.        
        if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
            // We "step" through the results - once for each row.
            while (sqlite3_step(statement) == SQLITE_ROW) {
                // The second parameter indicates the column index into the result set.
                int primaryKey = sqlite3_column_int(statement, 0);
                // We avoid the alloc-init-autorelease pattern here because we are in a tight loop and
                // autorelease is slightly more expensive than release. This design choice has nothing to do with
                // actual memory management - at the end of this block of code, all the book objects allocated
                // here will be in memory regardless of whether we use autorelease or release, because they are
                // retained by the books array.
                Book *book = [[Book alloc] initWithPrimaryKey:primaryKey database:database];
                [books addObject:book];
                [book release];
            }
        }
        // "Finalize" the statement - releases the resources associated with the statement.
        sqlite3_finalize(statement);
    } else {
        // Even though the open failed, call close to properly clean up resources.
        sqlite3_close(database);
        NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
        // Additional error handling, as appropriate...
    }
}
MasterViewController.m

ここでbooksからタイトルを取得し一覧のcell.textに設定している。

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
    if (cell == nil) {
        // Create a new cell. CGRectZero allows the cell to determine the appropriate size.
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyIdentifier"] autorelease];
    }
    // Retrieve the book object matching the row from the application delegate's array.
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    Book *book = (Book *)[appDelegate.books objectAtIndex:indexPath.row];
    cell.text = book.title;
    return cell;
}

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

AppDelegate.m
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
    NSLog(@"AppDelegate#initializeDatabase");	// デバッグ文
	
    NSMutableArray *bookArray = [[NSMutableArray alloc] init];
    self.books = bookArray;
    [bookArray release];
    // The database is stored in the application bundle. 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"bookdb.sql"];

    NSLog(@"path : %@",path);	// デバッグ文
	
    // Open the database. The database was prepared outside the application.
    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
        // Get the primary key for all books.
        const char *sql = "SELECT pk FROM book";
        sqlite3_stmt *statement;
        // Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
        // The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.        
        if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
            // We "step" through the results - once for each row.
            while (sqlite3_step(statement) == SQLITE_ROW) {
                // The second parameter indicates the column index into the result set.
                int primaryKey = sqlite3_column_int(statement, 0);
   
                NSLog(@"primaryKey : %d",primaryKey);	// デバッグ文

                // We avoid the alloc-init-autorelease pattern here because we are in a tight loop and
                // autorelease is slightly more expensive than release. This design choice has nothing to do with
                // actual memory management - at the end of this block of code, all the book objects allocated
                // here will be in memory regardless of whether we use autorelease or release, because they are
                // retained by the books array.
                Book *book = [[Book alloc] initWithPrimaryKey:primaryKey database:database];
                
                NSLog(@"====================");	// デバッグ文
                NSLog(@"book.primaryKey : %d",book.primaryKey);	// デバッグ文
                NSLog(@"book.title : %@",book.title);	// デバッグ文
                NSLog(@"book.copyright : %@",book.copyright);	// デバッグ文
                NSLog(@"book.copyright : %@",book.author);	// デバッグ文
                
                [books addObject:book];
                [book release];
            }
        }
        // "Finalize" the statement - releases the resources associated with the statement.
        sqlite3_finalize(statement);
    } else {
        // Even though the open failed, call close to properly clean up resources.
        sqlite3_close(database);
        NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
        // Additional error handling, as appropriate...
    }
}
MasterViewController.m
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"MasterViewController#tableView cellForRowAtIndexPath");	// デバッグ文
    
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
    if (cell == nil) {
        // Create a new cell. CGRectZero allows the cell to determine the appropriate size.
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyIdentifier"] autorelease];
    }
    // Retrieve the book object matching the row from the application delegate's array.
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    Book *book = (Book *)[appDelegate.books objectAtIndex:indexPath.row];

    NSLog(@"book.title : %@",book.title);	// デバッグ文

    cell.text = book.title;
    return cell;
}

アプリケーション起動後のスクリーンショット

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

思ったとおりの動作になっていることを確認できた。

2008-11-30 18:59:56.598 SQLiteBooks[27063:20b] AppDelegate#initializeDatabase
2008-11-30 18:59:56.598 SQLiteBooks[27063:20b] path : /Users/kuru/Library/Application Support/iPhone Simulator/User/Applications/8CD7D8A9-8B28-4A56-A507-20639F4CDA5E/Documents/bookdb.sql
2008-11-30 18:59:56.602 SQLiteBooks[27063:20b] primaryKey : 1
2008-11-30 18:59:56.602 SQLiteBooks[27063:20b] ====================
2008-11-30 18:59:56.603 SQLiteBooks[27063:20b] book.primaryKey : 1
2008-11-30 18:59:56.603 SQLiteBooks[27063:20b] book.title : War and Peace
2008-11-30 18:59:56.603 SQLiteBooks[27063:20b] book.copyright : (null)
2008-11-30 18:59:56.604 SQLiteBooks[27063:20b] book.copyright : (null)
2008-11-30 18:59:56.605 SQLiteBooks[27063:20b] primaryKey : 2
2008-11-30 18:59:56.607 SQLiteBooks[27063:20b] ====================
2008-11-30 18:59:56.607 SQLiteBooks[27063:20b] book.primaryKey : 2
2008-11-30 18:59:56.608 SQLiteBooks[27063:20b] book.title : Mac OS X Internals
2008-11-30 18:59:56.609 SQLiteBooks[27063:20b] book.copyright : (null)
2008-11-30 18:59:56.612 SQLiteBooks[27063:20b] book.copyright : (null)
2008-11-30 18:59:56.616 SQLiteBooks[27063:20b] primaryKey : 3
2008-11-30 18:59:56.616 SQLiteBooks[27063:20b] ====================
2008-11-30 18:59:56.616 SQLiteBooks[27063:20b] book.primaryKey : 3
2008-11-30 18:59:56.617 SQLiteBooks[27063:20b] book.title : The Divine Comedy
2008-11-30 18:59:56.617 SQLiteBooks[27063:20b] book.copyright : (null)
2008-11-30 18:59:56.617 SQLiteBooks[27063:20b] book.copyright : (null)
2008-11-30 18:59:56.621 SQLiteBooks[27063:20b] MasterViewController#tableView cellForRowAtIndexPath
2008-11-30 18:59:56.622 SQLiteBooks[27063:20b] book.title : The Divine Comedy
2008-11-30 18:59:56.647 SQLiteBooks[27063:20b] MasterViewController#tableView cellForRowAtIndexPath
2008-11-30 18:59:56.648 SQLiteBooks[27063:20b] book.title : Mac OS X Internals
2008-11-30 18:59:56.649 SQLiteBooks[27063:20b] MasterViewController#tableView cellForRowAtIndexPath
2008-11-30 18:59:56.649 SQLiteBooks[27063:20b] book.title : War and Peace

次は入力したデータを保存する動作を確認する。