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:
select *
" up there)??? – Complacency