2011-12-06 4 views
1

これで、私は約1週間この壁に頭を打ちました。iPhoneのSQLite3 - insertはエラーコード8を返しますreadonlyデータベースを書き込もう

私は、そこにsqliteデータベースを持つiPhoneアプリを書いています。私はデータベースを開いてそこから読み込むことができます(私はいくつかのテストデータをコマンドライン/ターミナル経由でそこに入れます)、特定のデータを選択することができます。しかし、私は電話からデータベースに挿入することはできません。 sqlite3_exec(...)を実行すると、エラーコード8「読み取り専用データベースの書き込みを試みます」が返されます。

私はメインバンドルのデータベースを使用していてユーザデータベースではないことを他の質問で読んでいました。シミュレータはライブデバイスではエラー。さて、私の場合はそうではありません。私はこのエラーをシミュレータで実行しています。そして、私のコードがデータベースをチェックするために言うことができるのは、他の多くの人がそれを推薦するのとまったく同じです。

ここで私はデータベースが存在を確認するために使用し、そうでない場合、私はそれをコピーしたコードです:

// initialize db (if not already) 
+(void) checkDatabase { 
    // setup some variables 
    Boolean success; 
    dbName = @"daarma.sqlite"; 
    NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDirectory, YES); 
    // I have tried this with both NSUserDirectory and NSUserDomainMask, desn't seem to make a difference 
    NSString *documentsDir = [documentPath objectAtIndex:0]; 
    dbPath = [documentsDir stringByAppendingPathComponent:dbName]; 
    // dbPath = [[NSBundle mainBundle] pathForResource:@"daarma" ofType:@"sqlite"]; 

    // check to see if the database already exists 
    NSFileManager *fm = [NSFileManager defaultManager]; 
    success = [fm fileExistsAtPath:dbPath]; 
    if(success) { 
     NSLog(@"Database exists, returning."); 
     return; 
    } 

    // if not, we create it 
    NSLog(@"Creating database in user profile..."); 
    NSString *dbPathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbName]; 
    [fm copyItemAtPath:dbPathFromApp toPath:dbPath error:nil];  

    [fm release]; 
    [documentPath release]; 
    [documentsDir release]; 
} 

私はこれを使用してデータを挿入するために行くとき:

sqlite3 *db; 
int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL); 
if(open == 0) { 
    NSLog(@"open, inserting"); 
    NSString *sql = [NSString stringWithFormat:@"insert into affiliates values('1','2','3','4','5','6','7','8','9','10','11','12')"]; 
    int exec = sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL); 
    NSLog(@"exec = %d",exec); 
} 
sqlite3_close(db); 

幹部は、上記のエラーコード8で返されます: ""読み取り専用データベースを書き込もうとしました。 "

通常の再起動、プロジェクトのクリーニング、シミュレータデータのリセットを試みました。私はSimu latorディレクトリにコピーし、すべてのアプリケーションデータを手動で削除しました。私が戻ってみると、データベースはそこになかったと認識し、それをコピーしましたが、私はまだそのエラーを受け取ります。

編集:私はちょうど私がcheckDatabase方法でこれを行う場合は気づいた

NSError *error; 
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error]; 
NSLog(@"error = %@",error); 

が、それは最初は(コンテンツのリセットを行った後に)回るクラッシュするシミュレータを引き起こし、それ以降はクラッシュなしで上記のエラーを再開します。だから、私は私のcheckDatabaseメソッドで何か間違っていると思います。 ?? :(それは私にエラーメッセージの出力を指示することはありません

答えて

1

私はあなたのコードを試みたが、それは次の行にオープン= 21(SQLITE_MISUSE)で失敗しました:。あなたが渡すので-1に

int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL); 

flagsパラメータ。それはSQLITE_OPEN_READWRITEでなければなりません。

私はいくつかのより多くのコメントがある。

[fm release]; 
[documentPath release]; 
[documentsDir release]; 

あなたは、/ INITをALLOC保持、またはそれらをコピーしていないため、これらのリリースの、必要ありません。

NSString *sql = [NSString stringWithFormat:@"insert into affiliates values('1','2','3','4','5','6','7','8','9','10','11','12')"]; 
int exec = sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL); 

SQLの場合は、stringWithFormat:の代わりにsqlite3_prepare_v2とバインドパラメータを使用する必要があります。

if(open == 0) { ... } 

可能な限り、マジックナンバー(0)の代わりにシンボリック定数(SQLITE_OK)を使用する必要があります。

NSError *error; 
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error]; 
NSLog(@"error = %@",error); 

copyItemAtPath:を呼び出す前にerror = nilを初期化する必要があります。これは、コピー操作が成功したときにエラーが変更されないためです。

+0

のObjective-C /皮肉を学ぶの喜び。あなたのご意見をありがとうございます!私はそれらを試してコメントしたり、答えをマークしたりします。 – rollhax

+0

これはうまくいった!私は馬鹿のように感じる。再度、感謝します! – rollhax

2

この

sqlite3_open_v2([dbPath UTF8String], &db, SQLITE_OPEN_READWRITE , NULL); 

や、基本的に開いている機能を変更しようと些細なオープン機能を使用

Sqlite3_open([dbPath UTF8String],&db);// this should do the job 

役立ちます希望:)

関連する問題