所以,我已经在这上面撞墙了大约一个星期了。
我正在编写一个包含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);
exec返回上面提到的错误代码8:“”尝试编写只读数据库。“
我还尝试了通常的重启,清理项目,重置模拟器数据。我甚至进入了我的Simulator目录并手动删除了所有应用程序数据。当我试图重新进入时,它认识到数据库不在那里并将其复制过来,但我仍然遇到了这个错误。
编辑:
我刚刚注意到,如果我在checkDatabase方法中执行此操作:
NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error];
NSLog(@"error = %@",error);
它导致模拟器在第一次运行时崩溃(在执行内容重置之后),但每次之后它恢复上述错误而没有崩溃。所以也许我在使用checkDatabase方法做错了。 ?? :(它永远不会告诉我错误信息的输出。
答案 0 :(得分:2)
尝试将open功能更改为此
sqlite3_open_v2([dbPath UTF8String], &db, SQLITE_OPEN_READWRITE , NULL);
或基本上使用普通的开放功能
Sqlite3_open([dbPath UTF8String],&db);// this should do the job
希望有所帮助:)
答案 1 :(得分:1)
我尝试了您的代码,但在以下行中使用open = 21(SQLITE_MISUSE)失败了:
int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL);
因为您将-1传递给flags参数。它应该是SQLITE_OPEN_READWRITE。
我还有一些意见。
[fm release];
[documentPath release];
[documentsDir release];
这些版本不是必需的,因为您不会分配/初始化,保留或复制它们。
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);
你应该使用sqlite3_prepare_v2并绑定参数而不是stringWithFormat:for SQL。
if(open == 0) { ... }
尽可能使用符号常量(SQLITE_OK)而不是幻数(0)。
NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error];
NSLog(@"error = %@",error);
您应该在调用copyItemAtPath之前初始化error = nil:因为复制操作成功时错误不会更改。