将SQLite数据库从bundle复制到文档然后查询时崩溃

时间:2016-01-07 16:33:55

标签: objective-c multithreading sqlite grand-central-dispatch exc-bad-access

这对我来说毫无意义。

当查询将数据库从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

0 个答案:

没有答案