It’s been a while I wanted to write a note about the “C blocks” but because of lack of time and inspiration I have postponed this task again and again. I’m finally here however. This post aims to provide a summary of what is blocks and how to use them in an Objective-C context. I also took this opportunity to provide a little blocks cheat sheet in order to have a quick access to information.
Blocks? What is that?!
Blocks are a programming concept designed by Apple and added as a nonstandard extension to the C (it means the blocks can also be used in C++, Objective-C 2.0 and Objective-C++). They are natively supported on Mac OS X v10.6 and later, and iOS 4.0 and later.
Trying to be precise and concise a block (also named closure or lambda-expression in another language) is an inline anonymous function which can capture the variables available in its context at the run-time (from the stack and/or the heap).
Why use them?
Blocks are often useful when you need callbacks or delayed execution by passing them as parameters to another methods. Moreover blocks has been designed by Apple in order to make the concurrent programming easier with the GCD (Grand Central dispatch) threading architecture.
Unlike function pointers, blocks are anonymous and can therefore be declared inline on the method call which saves a lot of line of code. Furthermore when you define a block, it makes a snapshot of its current lexical scope which allows you to easily work with variables that surround it.
An another detail which is important during the iOS or Mac development is that in an Objective-C context, blocks are full-fledged objects, meaning they can be copied and retained just like any other object.
All these features make the blocks a very interesting concept in many cases, to make your code more concise and robust and therefore much more readable and maintainable.
Before to show you some example, I’m going to introduce you the syntax of the “C blocks” and explain you on how to read/construct them.
Syntax of blocks
To begin with blocks the most simple is to explain its syntax (people who know the function pointers will not be surprised). Here is the syntax:
type (^block_name) (type_arguments) = ^return_type(type arguments) { /* body */ };
The most confusing for a beginner is certainly the block’s declaration. Here the quick steps to declare a block:
- Declare a variable: block_name.
- Dereference it to yield block information: (^block_name).
- Add its return type and its input parameters: type (^block_name) (type_arguments).
The creation is much simpler:
- Define that is a block using the caret character: ^.
- Mention the return type of the block: ^ return_type.
- Add the input arguments of the block: ^ return_type (type arguments).
- Write the block’s body: ^ return_type (type arguments) { /* body */ }.
Some parts of a block assignment are optionals:
- If the block takes no arguments, the argument list can be skipped.
- Example: ^ BOOL { return YES; }.
- You don’t need to specify the return type because it can be inferred by the compiler from the return statement.
- Example: ^ (NSString *s) { /* body */ return YES; }.
The __block Storage Type
One of the characteristics of blocks is that they can capture the variables that are visible to their scope. This is what is called a closure. When you capture a variable, its value is copied into the stack (as a constant), ie you can just read it and not modify it.
Fortunately, you are able to modify the variables inside a block by prefixing them with the __block storage type modifier. This will copy their addresses/references instead of their value.
Let’s make a little example which use the __block keyword to illustrate the concept:
__block int x = 0; // Use the __block keyword to be able to modify it into the block
// Create a block to increment the given variable
void (^increment) () = ^ { x++; };
NSLog(@"%d", x); // Display "0"
increment();
NSLog(@"%d", x); // Display "1"
In this example we declare a variable named “x” (prefix with the __block keyword). Then we declare a block named “increment” which caught the “x” variable. Each time we call the “increment” block, the variable is incremented. It’s possible because the variable is prefixed with the __block storage type modifier. If we remove it, the compiler gives us this error: “error: Semantic Issue: Variable is not assignable (missing __block type specifier)“.
Copy / Release
When you create a block, unlike other objects, this one is created on the stack ie that your block will live only within its declaration scope. So if you want use your block everywhere in your code for example you will need to move it on the heap to avoid its deletion. To do so you will have to use the Block_copy C function (We will see later what it will serve you). To avoid a memory leak you must always use a Block_release function with a Block_copy function.
Well, we have talk enough about the theory. The next part will show you how to use them with some example.
Blocks in practice
In this section we are going to show you how to work with blocks (in Objective-C in the most case) using some examples.
Hello World!
To start, here a little block which display a “Hello Wold!” on the console:
^ void (void) {
NSLog(@"Hello World!"); // Print "Hello World!"
}(); // () calls the block
// Equivalent block because it returns nothing and it takes no arguments
^ {
NSLog(@"Hello World!"); // Print "Hello World!"
}(); // () calls the block
This is the easiest way to use a block. In this case, the blocks are anonymous and are called directly after they definition.
Fade a UIView
To illustrate the blocks with a concrete example we are going to work with views. Since iOS 4.0 and the introduction of blocks, Apple has added a lot of convenience API using the powerfull of blocks in order to facilitate our work, like for the view animations. Before, to write a simple fade in (or fade out) animation you needed several line of codes as showing in the sample code bellow:
[aView setAlpha:1.0f]; // Set the initial view's alpha
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[aView setAlpha:0.01f]; // Set the final view's alpha
[UIView commitAnimations]; // Commit and run the animation
Now, to do the same thing with CocoaTouch and the blocks it is very simple. In the following example we have a UIView with an original alpha of 1.0f that we will fade to 0.01f in 2 seconds:
[aView setAlpha:1.0f]; // Set the initial view's alpha
[UIView animateWithDuration:2.0f
animations:^ { [aView setAlpha:0.01f]; }];
That’s all! The UIView “animateWithDuration:animations:” method take in first argument the animation duration and in second argument a block which return nothing and take no argument. The block animation capture the aView object and set its alpha to 0.1f. As you can see, you can do the same thing as before but with only “one instruction” thanks to the blocks. If you want learn more about view animation I suggest you visit this post from the Ray Wenderlich’s blog.
Return a block
The blocks are very useful to factor out or make generic pieces of code. To do this, are generally used functions that take input arguments to configure the block which is returned. The following example aims to explain you how and why a function which return a block may be useful.
Imagine that you need functions that just raise a number to a predefined power. With blocks you can create a function which takes an exponent in argument and return a block which takes an integer in input and returns the result of the power of these two numbers. As an example is worth a thousand words, here is the code source:
- (int (^) (int))blockRaisedToPower:(int)y
{
int (^block) (int) = ^ int (int x)
{
return pow(x, y); // Close the value of "y"
};
return Block_copy(block); // Attention: You have to copy the block to the heap
// if you want be able to use it elsewhere in your code
}
- (void)test
{
int (^square) (int) = [self blockRaisedToPower:2];
int (^cube) (int) = [self blockRaisedToPower:3];
int (^zenzizenzizenzic) (int) = [self blockRaisedToPower:8];
NSLog(@"%d", square(3)); // 9
NSLog(@"%d", cube(3)); // 27
NSLog(@"%d", zenzizenzizenzic(3)); // 6561
// Don't forget to release the blocks returned
Block_release(square);
Block_release(cube);
Block_release(zenzizenzizenzic);
}
Note: Zenzizenzizenzic means x8 (cf: wikipedia).
As you can see, in the first part we declare our function which help us then to create several predefined blocks in the “test” method.
The “blockRaisedToPower” creates firstly a block which closes the exponent (“y” variable) inside its body to use it later in the power calculation. Then the function returns the new block which has just been created. You can noticed that we have used the Block_copy function to move the block from the stack to heap. If we had not done that, the block was deleted at the end of the “blockRaisedToPower” declaration and we would have an EXC_BAD_ACCESS error.
The “test” method simply defines several blocks, here square, cube and zenzizenzizenzic, in order to calculate respectively the x2, x3 and x8. Of course, at the end of this method we have also release the blocks which are on the heap to avoid any leaks. From only one function, this allows you to create different blocks that have been set up at their creation.
Here is the same code but using the typedef and the Objective-C syntax to make the code more readable:
typedef NSInteger (^PBlock) (NSInteger); // Define a new block type named "PBlock"
- (PBlock)blockRaisedToPower:(NSInteger)y
{
PBlock block = ^ NSInteger (NSInteger x)
{
return pow(x, y);
};
return [[block copy] autorelease]; // copy is equivalent to Block_copy(block) in Objective-C
// We autorelease the block to respect the best practices of Cocoa Touch
}
- (void)test
{
PBlock square = [self blockRaisedToPower:2];
PBlock cube = [self blockRaisedToPower:3];
PBlock zenzizenzizenzic = [self blockRaisedToPower:8];
NSLog(@"%d", square(3)); // 9
NSLog(@"%d", cube(3)); // 27
NSLog(@"%d", zenzizenzizenzic(3)); // 6561
}
Callbacks
To finish with examples, we are going to talk about the implementation of callbacks (with blocks) using a concrete example.
AVAudioPlayer is a nice class to work with audio on iOS which offers only a delegate callback system based. So we are going to add a block callback system in order to make the code more compact.
Here is the YLAudioPlayer.h:
#import <AVFoundation/AVFoundation.h>
typedef void (^YLAudioPlayerBlock)(BOOL);
@interface YLAudioPlayer : AVAudioPlayer
{
@protected
YLAudioPlayerBlock delegateBlock;
}
- (id)initWithContentsOfURL:(NSURL *)fileURL usingBlock:(YLAudioPlayerBlock)delegate;
+ (id)audioPlayerWithContentsOfURL:(NSURL *)fileURL usingBlock:(YLAudioPlayerBlock)delegate;
@end
In the interface, we have just define 2 new methods in order to use a block as callback and a new block as instance variable of the player.
Here is the corresponding YLAudioPlayer.m:
#import "YLAudioPlayer.h"
@interface YLAudioPlayer ()
@property (nonatomic, copy) AudioPlayerBlock delegateBlock; // Attention: Copy the block and not retain it
@end
@implementation YLAudioPlayer
@syntesize delegateBlock;
- (void)dealloc
{
// Release the block because it has been copied
[delegateBlock release], delegateBlock = nil;
[super dealloc];
}
- (id)initWithContentsOfURL:(NSURL *)fileURL usingBlock:(YLAudioPlayerBlock)delegate
{
if ((self = [super initWithContentsOfURL:fileURL error:nil]))
{
self.delegateBlock = delegate;
self.delegate = self;
}
return self;
}
+ (id)audioPlayerWithContentsOfURL:(NSURL *)fileURL usingBlock:(YLAudioPlayerBlock)delegate
{
return [[[self alloc] initWithContentsOfURL:fileURL usingBlock:delegate] autorelease];
}
#pragma mark -
#pragma mark YLAudioPlayer Delegate Methods
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// Call the delegate
delegateBlock(flag);
}
@end
The 2 main method here are the init and the delegate method:
- initWithContentsOfURL:usingBlock: Create the new audio player, set itself as delegate and set copy the delegate block.
- audioPlayerDidFinishPlaying:successfully: When this delegate method is call, we call the delegate block.
To know how to use this class let’s go by writing a sample code:
YLAudioPlayer *ap =
[YLAudioPlayer audioPlayerWithContentsOfURL:aSoundResourceURL usingBlock: ^ (BOOL successfully)
{
if (successfully)
{
// do something
}
}];
[ap play]; // Play the sound
You just have to declare the audio player passing it the delegate block (and the resource) and then play the sound.
This pattern is very simple to deploy in your code, and it can save you a lot of time and pain in the future. You just have to be careful with the memory leaks and when you copy a block you must always release it when you have finished to you it.
Well, I think we have seen the main cases of use for the blocks. Now, we are going to recap the main point relevant to the blocks before to finish.
Summary
To finish, you will find here a small summary of what we have said before. You will find most of the examples in the cheat sheet.
Declaration
// Define a block which return nothing and takes as only argument a NSString *
void (^block_name)(NSString *);
// Doing the same thing using a typedef
typedef void (^MyBlockType)(NSString *);
MyBlockType block_name;
Assignment
// Assigning this block to the block_name variable
block_name = ^ void (NSString *parameter) { /* body */ };
Execution
// Call the block passing a NSString * as parameter
block_name(@"parameter name");
Mistakes to avoid
A block is created by default on the stack and not on the heap. So you have to be careful while using them because in some case your code can compile perfectly, but it does not work during the execution. The following example illustrates this problem:
void (^block_name) ();
if (...)
{
block_name = ^ { ... };
} else
{
block_name = ^ { ... };
}
block_name();
In this example the block is created either in the if or in the else statement. It means the block is copy into the stack during all the statement’s lifetime and is deleted when the statement is finished (“}“). So when the block is called, it’s already fell of the stack and you’ll have an error. To avoid this error you must use the Block_copy method to move the block from the stack to the heap.
void (^block_name) ();
if (...)
{
block_name = [^ { ... } copy]; // move the block on the stack
} else
{
block_name = [^ { ... } copy]; // move the block on the stack
}
block_name();
[block_name release]; // When you copy a block, think to release it
An other issue which can appear is the memory leak if you don’t take care about the reference counting. In Objective-C, when you reference an object (or an instance variable of the object) inside a block, it is retained to prevent its deletion (and so random EXC_BAD_ACCESS error). The following example shows a case where a reference deadlock can appear if you don’t be careful:
// MyClass.h instance variables
WhateverObject *anObject;
BOOL aBoolean;
// MyClass.m
anObject = [[WhateverObject alloc] initWithBlock: ^
{
NSLog(@"%d", aBoolean); // Possible retain cycle
}];
Here we created an object of type MyClass which contains two instance variables namely anObject and aBoolean. In the implementation anObject is created using a block which use the aBoolean instance variable. So if the block is retained by the anObject object, a retain cycle can appear. Indeed in this case self will retain the anObject which will hold itself the block, which will keep self because it uses an instance variable of self (See the diagram below).
To avoid this problem, the object variable must be marked with the __block storage type modifier. Using it the object that will be captured will not be retained. So here to avoid the memory leak we create a variable of type MyClass with the __block keyword which will be used onto the block like this:
// MyClass.h instance variables
WhateverObject *anObject;
BOOL aBoolean;
// MyClass.m
__block MyClass *selfBlockRef = self; // trick
anObject = [[WhateverObject alloc] initWithBlock: ^
{
NSLog(@"%d", selfBlockRef->aBoolean);
}];
The Cheat Sheet!
Before I forget, here is the download link: Block Cheat Sheet
It summarizes the main points which has been talked about before:
- Block definition
- Block declaration
- Block creation
- Block call
- Block storage type modifier
- Block copy / release
- Mistakes to avoid
Conclusion
I hope this article has helped you better understand some aspect of blocks and that the cheat sheet will make your job easier in the future. If you have any question or point to clarify don’t hesitate, comments are here for that. 😉
References
For further study or clarify some points you can follow these links:
- Blocks (C language extension), Wikipedia.
- Programming with C Blocks, Third Cog.
- Using Blocks in iOS 4: The Basics, The Pragmatic Studio.
- The ugly side of blocks: explicit declarations and casting, Cocoa with Love.
- Blocks Programming Topics, Mac OS X Developer Library.
- A Short Practical Guide to Blocks, iOS Developer Library.
Nice work on the cheat sheet, you will definitely save a lot of headaches with that. Blocks really are so amazing.
Thank you very much for your feedback and your share!
Yes, blocks are very useful in a lot of cases. The most difficult part is to assimilate the syntax and to pay attention to some weird cases.
Greetz
GREAT work, thanks a lot!
Only one little issue: “mistakes to avoid” – the “deadlock” isn’t really a deadlock but a retain cycle, is it?
Hey, thanks for the feedback.
Yes you have right, it’s my bad. I’m going to fix that now. 😉
Neat explanation. Organized concepts well. Useful.
Very nice tutorial and blocks cheat sheet :), thanks.
Thank you! It tooks a lot of times to do such articles so if it can be helpful that’s
I have never fully understood blocks till now. I mean, there is the documentation from Apple itself, but it’s so cryptic I might as well let my Literature teacher include it in our reading list. My exposure to blocks have been limited to code fragments from tutorials and open source projects on the web, which is enough to teach me the basic, but not all there is to know.
Another thing, your blog seems oddly unresponsive. Took me three reloads to view this blog post. Maybe this post got too popular for your server to handle? 😉
P.S. YOUR CAPTCHA MADE ME DO MATH YUCK
Hi,
Thank your for your feedback! I’m glad it helped you to clarify some points.
I don’t think have enough traffic on my blog to slow down the bandwidth (so may be a host problem), but if the issue becomes more recurent I’ll look at it more closely.
Thank you, again,
Yannick
P.S. Without captcha I receive a lot of spam and this one is understandable (In my opinion).
When doing the “return a block example” under ARC. Do you still have to copy the block or will the compiler handle it?
For me I get it to work with both approaches. So what is the correct way?
ARC manages blocks, like any other objects, and it knows that they have to be copied and not just retained. So in theory you don’t care about them in an ARC context as long as you use block types in your declarations/signatures instead of ‘id’.
For more information you can check this link. 😉
pretty cool job.Thank you for your share.
Hi,
Can you please help solving my problem listed at:
http://stackoverflow.com/questions/14604179/iphone-sdk-storing-the-block-parameter-for-later-use/14604719#14604719
BR,
Akshay Shah.
Hi, Very nice article. Thanks for writing
Really good article, but I would like to ask, how can I catch the return value of a method call that has two blocks as parameters??
ex.
typedef void (^AlertRowBlock)(NSIndexPath *selectedIndex);
typedef NSArray *(^AlertCompletionBlock)(bool cancelOrOKButton);
-(void)configureSelectionBlock:(AlertRowBlock)selBlock
andCompletionBlock:(AlertCompletionBlock)comBlock;
So, I would like to have access to the variable that is returned after the call to “AlertCompletionBlock”.
Do you know how to??
Thanks!!