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