[英]SQLite3 on iPhone - insert returns error code 8 attempt to write a readonly database
因此,大约一个星期以来,我一直在头上撞墙。
我正在编写一个包含sqlite数据库的iPhone应用程序。 我能够打开数据库并从中读取(我通过命令行/终端输入一些测试数据),选择特定数据等。但是,我不能做的是从手机插入数据库。 当我执行sqlite3_exec(...)时,它返回错误代码8“尝试编写只读数据库”。
我在这里读过其他问题,说我使用的是Main Bundle的数据库,而不是用户数据库,并且模拟器在运行的设备上经常会出现“让你做”的错误。 嗯,这不是我的情况下发生的事情 - 我在模拟器上运行时遇到此错误。 从我可以告诉我的代码来检查数据库正如许多其他人推荐的那样。
这是我用来验证数据库存在的代码,如果不存在,则将其复制:
// 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方法做错了。 ?? :(它从不告诉我错误消息的输出。
尝试将打开功能更改为此
sqlite3_open_v2([dbPath UTF8String], &db, SQLITE_OPEN_READWRITE , NULL);
或者基本上使用琐碎的开放功能
Sqlite3_open([dbPath UTF8String],&db);// this should do the job
希望有帮助:)
我尝试了您的代码,但以下行中的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:因为复制操作成功时不会更改错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.