Question

Here is the case. I got a singleton class call DBManager with sqlite3. And insert,delete,select are done via this class. suppose now ClassA need to insert a record to table a and ClassB need to select a record from table a. So the presudo code is like this.

Class A
[[DBManager getInstance] insertRecord:@"12345"];

Class B
-(void)processData{
    Record r = [[DBManager getInstance] getRecord];
    // working with record r. after that doing some layout update
    [self.lbTitle setText:r.name];
}

cause in my project, there are 4-5 class will access the db. So sometime a Database is locked error is throw and my app crashed. I know one of the solution is using GCD dispatch_async(CUSTOM_DB_QUEUE,block) using these block for all the codes related to the db. But if so, i need to also modify Class B like this. Am I right?

Class B
-(void)processData{
   dispatch_async(CUSTOM_DB_QUEUE,{
   [[DBManager getInstance] getRecord onRecordGot:^(Record* r) {
       // working with record r. after that doing some layout update
       dispatch_async(MAIN_QUEUE,{
       [self.lbTitle setText:r.name];
       )};
    }];
)};
} 

Is this approach correct?? so i need to change all my code in DBManager to return the result using block coding?? Is there any simple way for queue up the hold DBManager class??

Was it helpful?

Solution

There's a better approach. Do not make any changes to your code that calls DBManager. All changes should be made inside your DBManager class. And there is no reason to use dispatch_async. Use dispatch_sync.

This code stays the same:

Class A
[[DBManager getInstance] insertRecord:@"12345"];

Class B
-(void)processData{
    Record r = [[DBManager getInstance] getRecord];
    // working with record r. after that doing some layout update
    [self.lbTitle setText:r.name];
}

In your insertRecord: method you change it to something like:

- (void)insertRecord:(NSString *)record {
    dispatch__barrier_sync(CUSTOM_DB_QUEUE, ^{
        // original code to insert record
    };
}

And your getRecord method becomes:

- (Record *)getRecord {
    __block Record *result = nil;

    dispatch_sync(CUSTOM_DB_QUEUE, ^{
        // original code that sets result
    };

    return result;
}

By using dispatch_sync and dispatch_barrier_sync, this code allows for any number of concurrent calls to getRecord but only one call to insertRecord. It also ensures calls to getRecord are blocked while insertRecord: is being run.

OTHER TIPS

To make it thread safe, you can use pthread_mutex_t as a global instance. Lock/unlock this mutex according to its usage e.g.

pthread_mutex_t *dbLock;

Class A
pthread_mutex_lock(dbLock);

[[DBManager getInstance] insertRecord:@"12345"];

pthread_mutex_unlock(dbLock);

Class B
-(void)processData{
    pthread_mutex_lock(dbLock);

    Record r = [[DBManager getInstance] getRecord];
    // working with record r. after that doing some layout update
    [self.lbTitle setText:r.name];

    pthread_mutex_unlock(dbLock);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top