jeudi 7 janvier 2016

Crashes when copying SQLite db from bundle to documents and then querying

This makes absolutely no sense (to me).

SQLite will throw EXC_BAD_ACCESS errors randomly (on the sqlite3_prepare_v2 line in the Db class) when querying when I copy the database from the bundle to the documents folder in a background thread. But, if I don't perform it in a background thread then no crashes ever occur.

The reason I want to perform the operation in a thread is that it is quite large (~150MB).

My didFinishLaunchingWithOptions looks like this - the working script is commented out below the GCD thread:

- (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;
}

The database class looks like (_statement is defined in the .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

Aucun commentaire:

Enregistrer un commentaire