質問

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??

役に立ちましたか?

解決

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.

他のヒント

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);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top