iOSアプリを作ってみる(5) テーブルに書き込めない その1

だいたいアプリのひな形が出来て、表面上は思ったように動いていても、裏側というか中では思ったように動いていないというケースはよくあります。これから何回かは、そういう平たく言うと「バグつぶし」で気がついた事を書いていこうと思います。

ん?Updateができていない!?

このアプリでは、DBからの読み出しだけではなく更新処理もあります。具体的には、出題された問題に対してそれが正解だったのか不正解だったのかという記録を残しています。例えば次回実行時に、前回間違えたモノを自動で出題させるというような用途を想定しています。

該当するロジックはこの部分になります。

....
    // SQL Query preparation
    NSString* querySQL = [[NSString alloc] initWithFormat:@"INSERT OR REPLACE INTO CWStats (WID, NumOfTrial, Success, Failure, LastTrial, Status) VALUES ( %d, %d, %d, %d, \"%@\", \"%@\")", statusDetail.wordID, statusDetail.numTrial, statusDetail.cSuccess, statusDetail.cFailure, statusDetail.lastTrial, statusDetail.cStatus];
    
    const char *query_stmnt = [querySQL UTF8String];
    
    sqlite3_stmt *sqlStatement;
    if(sqlite3_prepare_v2(db, query_stmnt, -1, &sqlStatement, NULL) != SQLITE_OK){
        NSLog(@"Problem occured during preparing satement : udateStatsRecord");
    } else {
        if (sqlite3_step(sqlStatement) == SQLITE_DONE) {
            NSLog(@"Commit work");
        } else {
            NSLog(@"Commit failed");
        }
    }
....

いくつかサンプルを見てきて、それと同じようにこんなロジックを書いてみた訳ですが、実際に動かしてみると、DBが更新されていません。もう少し具体的に言うと、sqlite3_step(sqlStatement) == SQLITE_DONEの部分は常にSQLITE_DONEが返っているのにも関わらず、実際にDBテーブルをのぞくとエントリが増えていません。

ひょっとして、明示的にCommit文を発行しないとダメなんだろうかとか考えること半日。とある情報に突き当たります。「リソースファイルはRead onlyだよ。更新する場合はDocument directryに入れる必要があるよ」というものです。ということで、該当するソースコードをもう一度見てみます。今度は、SQLを発行しているところではなくてDBファイルをオープンして接続するところです。

....
    NSFileManager *fileMgr = [NSFileManager defaultManager];

    dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"ChineseWords.sqlite"];
    NSLog(dbPath);

    BOOL success = [fileMgr fileExistsAtPath:dbPath];
    if(!success) {
        NSLog(@"Main Database file not found '%@'.", dbPath);
    }
    if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)) {
        NSLog(@"Cannot open the main database file.");
    }
    NSLog(@"Main database file is available now!");
....

確かに深く意味を考えずにコーディングしてしまったのですが、"resourcePath"という文言が気になります。つまりChineseWords.sqliteというファイルはResourcePathにあってRead only状態になっているというのは間違えなさそうです。

ファイルはどこにあるの?

DBファイルを取得するときにNSLogでファイルの所在を吐き出していることを思い出し、ログを拾ってみました。

2013-09-07 11:19:40.125 PinyinTrainer[60567:c07] /Users/xxx/Library/Application Support/iPhone Simulator/6.1/Applications/901BB33A-31A8-4F56-A028-E025C662593E/PinyinTrainer.app/ChineseWords.sqlite

ふむふむ。Usersの下のLibraryフォルダのさらに深いところにあるようです。それなら同じところをFinderで見れば良いんだなと思ったのですが、Usersの下のLibraryフォルダが見つかりません。どうやら隠しフォルダになっていて、こんな方法を使わないと見れないとのこと。

自分のユーザフォルダを開いた状態で、メニューパスでGo-->Go to folderと選択して、

f:id:deutschina:20130907170156p:plain

Libraryと入力してやると、

f:id:deutschina:20130907170451p:plain

さらに *.app というのはフォルダではなくてパッケージになっているので、コンテキストメニューからパッケージの内容を表示と選んでようやく、この下の画面にたどり着けます。

f:id:deutschina:20130907170549p:plain

確かに、sqliteという拡張子を持ったファイルが見つかりました。

今ここにあるファイルをdocumentフォルダに持っていけば良いという事になるのでしょうが、そもそもそれはどこ?というところから、話はあらぬ方向に逸れていきます。

(つづく)