Blocks are an extension to the C language and thus fully supported in Objective-C.
There are two ways to use block:
- The most common way to use a block is to pass it to a method that in turn calls the block.
- Example: UIView animation block or array/dictionary enumeration block.
- Create a block variable and assign a block to it. Then call the block directly.
- Example: Here’s how to assign our block to a block variable called now:
Only declaration -
[sourcecode language=”objc”] void (^now)(void); [/sourcecode]
The name of the block variable is always preceded by a ^ and in parentheses. Block variables have an associated type. In this case, the now variable can reference any block that returns no value (the first void) and takes no parameters (the void in parentheses). Our block conforms to this type, so we can safely assign it to the now variable.
[sourcecode language=”objc”] /* * * * * Declaration with block - * (This will give you a warning of unused variable now.) */ void (^now)(void) = ^ { NSDate *date = [NSDate date]; NSLog(@”The date and time is %@”, date); };
// Here’s how we call our block - (This will remove above warning.) now();
[/sourcecode]
Examples:
[sourcecode language=”objc”]
/* * * * * A Block variable declaration * This will give you a warning of unused variable now. */
void (^example0)(void);
/* A Block body declaration * This will give you a warning of expression result unused. * ^ = The caret introduces a block literal. * {}; = The curly braces enclose statements makes the body of block. */
^ { NSLog(@”Current Date: %@”, [NSDate date]); };
/* * * Example 1. - Simple Print * Block variable declaration with void return type and void (no) parameter * Block calling with no arguments */
void (^example1)(void) = ^ { NSDate *date = [NSDate date]; NSLog(@”The date and time is %@”, date); };
example1();
// Example 2. - Note worthy print int x = 1; NSDate *date = [NSDate date]; void (^example2)(void) = ^ { NSLog(@”%d - %@”, x, date); };
example2();
sleep(5); date = [NSDate date]; x=2; example2();
/* Example 3. Variable Prints * With one parameter and int return type */
int (^triple)(int); triple = ^(int number) { return number * 3; };
int result = triple(1); NSLog(@”1. result: %d”, result);
/* * With two parameter and int return type */ int (^multiply)(int, int); multiply = ^(int x, int y) { return x * y; };
result = multiply(2, 3); NSLog(@”2. result: %d”, result);
[/sourcecode]
Instead of using raw types, I have typedef’d the blocks to simplify it. My experience is that it hurts really badly to not use type definitions, and sometimes it becomes so complicated that it won’t even compile. Just like with function pointers, always define block types to simplify your code.
[sourcecode language=”objc”]
/* * Example 4. Using typedef */
typedef void (^JSVoidBlock)();
typedef NSString* (^blockNameWithType) (double val); blockNameWithType testOne; // _strProperty = [@”zeeshan” uppercaseString]; strInstanceVar = [@”zeeshan” uppercaseString];
testOne = ^ (double newVal){ // NSLog(@”Old val : %@”, strInstanceVar); // _strProperty = [@”khan” uppercaseString]; strInstanceVar = [@”khan” uppercaseString]; return @”Block return value”; }; NSLog(@”Block val: %@”, testOne(23.0));
[/sourcecode]
Important Notes:
- The block takes a (read-only) snapshot of all the variables in scope that the block uses.
- The block variable looks like a function pointer and calling the block is similar to calling a function. But unlike function pointers, blocks are actually Objective-C objects. And that means we can pass them around like other objects.
- The block that is returned by some function is copied, and then autoreleased. This is because blocks begin life on the stack, and not on the heap. If the block is not copied onto the heap, it will be lost once it is out of scope; if it is not autoreleased, it will be leaked, for UIBarButtonItem retains a copy of the block as an associated object.
- We can use local variable inside the block, but that variable would be READ ONLY until we add __block in front of that variable declaration.
- BOOL with blocks (BOOL *stops): Boolean is actually a BOOL Star because it a kind of an outgoing argument, that is going to pass you all the keys and values in this dictionary one at time in the block.
- Block keeps the strong pointer to objects referenced inside of them. (those are used inside the block).
Issue with Blocks:
Memory Cycle - the only Problem with using block:
[sourcecode language=”objc”] /* * Using a property */
@property (non atomic, strong) NSArray *myBlocks; [self.myBlocks addObject:^(){ [self doSomething]; }];
[/sourcecode]
In this case, self is an object referenced in this block. Thus the block will have a strong point to self.
But notice that self also has a strong pointer to the block through its myBlocks property.
So, Neither self not the block can ever escape the heap now.
That’s because there will always be a strong pointer to both of them (each other’s pointer).
This is called a Memory Cycle.
How to solve:- Use __Weak MyClass *weakSelf = self;