这对我来说毫无意义。
当查询将数据库从bundle复制到后台线程中的documents文件夹时,SQLite将随机抛出EXC_BAD_ACCESS
错误(在Db类的sqlite3_prepare_v2
行上)。但是,如果我不在后台线程中执行它,那么就不会发生崩溃。
我想在一个线程中执行操作的原因是它非常大(~150MB)。
我的didFinishLaunchingWithOptions
看起来像这样 - 工作脚本在GCD线程下面注释掉了:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
dispatch_queue_t setupDb = dispatch_queue_create("setupDb", NULL);
dispatch_async(setupDb, ^{
[Db setup];
dispatch_async(dispatch_get_main_queue(), ^{
[Db connect];
[[NSNotificationCenter defaultCenter] postNotificationName:@"databaseReady" object:nil];
});
});
// If using this code, though, it works perfectly fine
// [Db setup];
// [Db connect];
// [[NSNotificationCenter defaultCenter] postNotificationName:@"databaseReady" object:nil];
return YES;
}
数据库类看似{_statement
中定义了.h
):
@implementation Db
static sqlite3 * _db;
static NSString * _dbPath;
+ (BOOL)setup {
NSString * sqlBundlePath = [[NSBundle mainBundle] pathForResource:@"db" ofType:@"sqlite"];
NSString * documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString * sqlDocumentPath = [[documentsFolder stringByAppendingPathComponent:@"db"] stringByAppendingPathExtension:@"sqlite"];
NSFileManager * fileManager = [NSFileManager defaultManager];
// Make sure we don't already have the database in our documents, we don't want to overwrite!
if (! [fileManager fileExistsAtPath:sqlDocumentPath]) {
BOOL success = [fileManager copyItemAtPath:sqlBundlePath toPath:sqlDocumentPath error:nil];
if (! success) {
NSLog(@"Error copying database");
return NO;
}
}
_dbPath = sqlDocumentPath;
return YES;
}
+ (BOOL)connect {
sqlite3_config(SQLITE_CONFIG_SERIALIZED);
sqlite3_open([_dbPath UTF8String], &_db);
return YES;
}
- (BOOL)prepare:(const char *)sql {
if (! sqlite3_prepare_v2(_db, sql, -1, &_statement, NULL) == SQLITE_OK) {
NSLog(@"Error whilst preparing query: %s", sqlite3_errmsg(_db));
sqlite3_finalize(_statement);
return NO;
}
return YES;
}
- (BOOL)step {
if (sqlite3_step(_statement) == SQLITE_ROW) {
return YES;
}
return NO;
}
- (void)finalise {
sqlite3_finalize(_statement);
}
@end