SQLite Database with FMDatabase Framework

I am using the SQLite shell of the FMDatabase in Objective-C and I have the following problem:

I run XML parsing and inserting the database into the background thread for some content that the user does not have access to, however the user can interact with the user interface and database from the section in which they are located.

The FMDatabase <FMDatabase: 0x17b7b0> is currently in use. 

In random order, I get a notification โ€œFMDatabase is already in useโ€ and the array will never be populated with the database. I got the impression that the FMDatabase class will process the request when it becomes free, but I have:

 while(contents.count < 1){ sleep(1); } 

Hoping that as soon as the database is free, the array will be full. I also tried restarting the massive collection of script if the database is busy, but to no avail.

Sorry if this question is confusing, I am happy to clarify.

+7
source share
2 answers

I had the same problem.

I switched to FMDatabaseQueue for every database query / update that I had to do. It works like a charm!

Using performSelectorOnMainThread is a good idea, but when it comes to actual coding, it can be quite difficult to pass your arguments and get results for future reference.

EDIT: here is a small example

 -(void) updateTaskStateAsync:(NSNumber *)taskID withNewStatus:(NSNumber *)state andCompletionBlock:(void(^)(BOOL status))completionBlock{ NSString *errInfo = [NSString stringWithFormat:@"taskID %d - state %d", [taskID intValue], [state intValue]]; [queue inDatabase:^(FMDatabase *db) { BOOL r = [db executeUpdate:@"UPDATE tasks SET state=?, date_job_last_updated=? WHERE identifier=?", state, [NSDate dateWithTimeIntervalSinceNow:0], taskID]; DB_DISPLAY_ERROR(errInfo); // convenient macro to log errors if(completionBlock) completionBlock(r); }]; } -(BOOL) updateTaskStateSync:(NSNumber *)taskID withNewStatus:(NSNumber *)state { NSString *errInfo = [NSString stringWithFormat:@"taskID %d - state %d", [taskID intValue], [state intValue]]; __block BOOL r = NO; __block BOOL ended = NO; [queue inDatabase:^(FMDatabase *db) { r = [db executeUpdate:@"UPDATE tasks SET state=?, date_job_last_updated=? WHERE identifier=?", state, [NSDate dateWithTimeIntervalSinceNow:0], taskID]; DB_DISPLAY_ERROR(errInfo); // convenient macro to log errors ended = YES; }]; NSCondition *cond = [[NSCondition alloc] init]; [cond lock]; while(!ended) [cond wait]; [cond unlock]; return r; } 
+7
source

You are facing this problem because your application is multi-threaded and you are accessing the same FMDatabase from different threads. A similar question, but for Python, can be found here .

FMDatabase is a sqlite API wrapper. sqlite does not allow concurrency by default, so FMDatabase uses a member variable called "inUse" for tracking. To fix the problem, try one of these methods defined in NSObject so that all calls in FMDatabase take place on the same thread.

  • performSelectorOnMainThread: withObject: waitUntilDone:
  • performSelectorOnMainThread: withObject: waitUntilDone: modes:
  • performSelector: onThread: withObject: waitUntilDone:
  • performSelector: onThread: withObject: waitUntilDone: modes:
+4
source

All Articles