Blocks are used for various things. The way you use them can make them very powerful.
For example, blocks are often used as a way to do what delegate methods usually do, that is they are passed as parameters and stored aside, then called later when some operation is finished. In that way, they can be used as "asynchronous operations" in the fact that they can be called at a later time.
Example of a usage where blocks can be seen as asynchronous is when they are called in a delegate method to make it easier to use than the delegate:
typedef void (^BlockAlertViewCompletion)(UIAlertView* alert, NSInteger clickedButton);
@interface BlockAlertView : UIAlertView <UIAlertViewDelegate>
-(void)showWithCompletion:(BlockAlertViewCompletion)completion;
@property(nonatomic, copy) BlockAlertViewCompletion completionBlock;
@end
@implementation BlockAlertView
@synthesize completionBlock = _completionBlock;
-(void)showWithCompletion:(BlockAlertViewCompletion)completion;
{
// Store the block for latter use
self.completionBlock = completion;
self.delegate = self; // Make ourselves as the delegate of UIAlertView
[self show];
}
// Then much later, the delegate method will be called ASYNCHRONOUSLY
-(void)alertView:(UIAlertView*)alert clickedButtonAtIndex:(NSInteger)buttonIndex
{
// Then call the block here to signal the called a button has been clicked
self.completionBlock(alert, buttonIndex);
}
-(void)dealloc { [_completionBlock release]; [super dealloc]; }
@end
// Usage:
BlockAlertView* alert = [[[BlockAlertView alloc] initWithTitle:@"Hello" message:@"Hello World!" delegate:nil cancelButtonTitle:@"Hi yourself" otherButtonTitles:@"I'm not very polite",nil];
// This will show the alert immediately (will call [alert show] eventually)
[alert showWithCompletion:^(UIAlertView* alert, NSInteger btnIndex)
{
// But this code in the block will only be called when the delegate method
// of UIAlertView will be triggered, so this code will be executed asynchronously / later, and not right away
NSLog(@"Button %d clicked", btnIndex);
}];
// So after the alert view has been shown on screen, the rest of the code below will continue executing
NSLog(@"The alert view has been shown on the screen, but the completionBlock passed a the parameter to showWithCompletion: has not been executed yet and will only execute when the delegate method is called");
[alert release];
Blocks don't really execute independently to other code strickly speaking. The are basically function pointers with context addded to capture surrounding variables. They can be executed in whatever thread you want. If you execute them directly in the current thread, like in the example below, they are not concurrent with the other code:
// Declare some block
dispatch_block_t block = ^{ NSLog(@"Hello world"); };
// Execute it right away
block(); // this executes the same way that is you have wrote the NSLog here, so this is not concurrent with the rest of the code.
But using GCD, you can add a block to a GCD queue on an independent thread and ask that thread to execute that block. In that sense, the code declared in the block is executed independently from the rest of the application
dispatch_block_t block = ^{ NSLog(@"Hello world"); };
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// Execute the block on a secondary queue, in parallel with the current code. This is concurrent execution, the block will execute independently to the rest of the code.
dispatch_async(queue, block);
You can also interpret the think that "block executes independently to other code" in the sense that they capture their contexte and the variables they need, and can be executed later with the values of these varariables captures when the block was created… even if the variables have changed and/or are out of scope:
-(void)createBlockAndCaptureVariables
{
int a = 5;
int b = 12;
// Create a block. It will capture the values of a and b at that time
dispatch_block_t block = ^{ NSLog(@"a*b = %d", a*b); };
// Even if you change the values of a and b later…
a = 7;
b = 25;
// when you execute the block here, it won't be affected by the fact that a and b have changed
[self testBlock:block]; // Will log a*b = 60
}
-(void)testBlock:(dispatch_block_t)aBlock
{
// And the block can be executed here and print the value of a*b, even if a and b
// Are out of scope and not accessible in this testBlock method.
aBlock();
}
Hope those little examples helps.