Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FMDatabaseQueue How To Return A Value

Tags:

ios

fmdb

I'm using FMDatabaseQueue in my iOS application. I'm stuck in understanding how to return the value upon creating the queue. Appreciate your help!!

 FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 

[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];

FMResultSet *rs = [db executeQuery:@"select * from foo"];
while ([rs next]) {
    ... 
}
// I want value to be returned from here
}];
like image 283
Ethan Sakhai Avatar asked May 27 '13 03:05

Ethan Sakhai


1 Answers

It depends upon what you're trying to return. But what might be confusing you is that if you issue a return statement from inside the inDatabase block, you're returning from the block, you're not returning from the method that contains this inDatabase block.

So, you simply don't return values from the inDatabase block, but rather you return values from outside the block. So what you'll commonly do, is you'll declare your variable to be returned outside the inDatabase block, your inDatabase block will update it, and then, when the block is done, that's when you return the results (not from within the inDatabase block).

A common example is if you're building an NSMutableArray: So create the mutable array outside of the block, and then add values from within the block, but then return the results after you exit the inDatabase block:

NSMutableArray *results = [NSMutableArray array];   // declare this outside the block

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 

[queue inDatabase:^(FMDatabase *db) {

    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @(1)];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @(2)];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @(3)];

    FMResultSet *rs = [db executeQuery:@"select * from foo"];
    while ([rs next]) {
        ... 
        [results addObject:result];                 // add values inside the block
    }
    [rs close];
}];

return results;                                     // return the results outside the block

Or, if you're dealing with some fundamental type, like a NSInteger or BOOL or what have you, you'd declare the variable with a __block qualifier. For example, I'll use this to return a BOOL success variable, e.g.:

__block BOOL success;                               // again, define outside the block

NSMutableArray *results = [NSMutableArray array];
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 

[queue inDatabase:^(FMDatabase *db) {

    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @(1)];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @(2)];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @(3)];

    FMResultSet *rs = [db executeQuery:@"select * from foo"];
    if (!rs)
    {
        NSLog(@"%s: %@", __FUNCTION__, [db lastErrorMessage]);
        success = NO;     // set the value inside the block
        return;           // note, this doesn't exit the method; this exits this `inDatabase` block
    }

    while ([rs next]) {
        ... 
    }

    [rs close];
    success = YES;        // another example of setting that `success` variable
}];

// so whether I successfully completed the block, or whether I hit the `return` 
// statement inside the block, I'll fall back here, at which point I'll return my
// boolean `success` variable

return success;           // don't return the value until after you exit the block

While this might seem confusing the first time you encounter it, it's useful to understand this. When you start using GCD block a lot, this pattern is very common. When you have a block (indicated by the ^ character), you almost have to think of it as an function that you're defining inside your main method. When you encounter a return inside a block, you're returning to the method that contains the block.

For introductions to blocks see:

  • A Short Practical Guide to Blocks

  • Blocks Programming Topics

like image 189
Rob Avatar answered Oct 15 '22 13:10

Rob