Pages

Friday 23 March 2012

Blocks Programming in iOS

Hello friends!!
In this post i am going to talk about "Blocks programming in iOS". iOS4 and latter supports blocks programming.

Blocks:
     Blocks are code snippet that can be use as a function or can be written as inline code at time of method invocation.

I think defining blocks is wasting of time because i can not define whole thing about blocks as it has lots of features , lots more than the above definition. You will get good understanding of blocks programming by examples of course! because examples are good way to explain anything.Let's start

Syntax to declare inline block:
     
^(parameter list){
   //you code
}

Inline block means blocks defined at time of function call.Caret (^) indicate the start of block literal and curly braces {} indicate the body of block.For example -
//following method use the block to print the square of given number 
-(void)printSquareOf:(NSInteger)number byExecutingBlock:(int(^)(int))block{

    NSLog(@"Square of %i = %i",number,block(number));
    //you can call block same as c functions 
    //syntax to call block using block name - blockName(commas separated parameter list)
    //like block(number); block1() and so on 
}

//call above method to print the square fo desire number
//block will square the given number and called method will print result in log

[self printSquareOf:4 byExecutingBlock:^(int n){return n*n;}];

OUTPUT:                                                                                                                             
   Square of 4 = 16                                                                                                                

We have define a inline block at line number 13 which take a integer as parameter and returns square of that number and "printSquareOf: byExecutingBlock: " prints the result.You can declare block as function argument like -

(return_type(^)(parameters list))block_name
For examples -
-(void)myLog:(void(^)())block;
-(void)printSquareOf:(NSInteger)number byExecutingBlock:(int(^)(int))block;
We need to writes inline blocks again and again, thats not good, now question is how can we writes once and use many times? of course we can do it by assigning blocks to a block variable, call blocks using block variable. 
Syntax to declare a block Variable -
  returnType (^blockVariableName)(parametersTypeList);
For example - 
  void(^now)(void);
  void(^doSquare)(int);
  void(^sayHelloTo)(NSString*);

Syntax to assign block literal to block variable -
  blockName = ^(parameterList){};

Following example shows that how to declare block variables and assign block literal in two different steps

    //declare block variable
    void(^sayHello)(void);//sayHello is block variable name
    //assign block literal to block variable sayHello
    sayHello = ^{NSLog(@"Hello,I am coding for bugs");};
    
    //call block using block variable
    sayHello();

In above example we have declare block variable at line number 2 which return type is void, name is "sayHello" and it does not accept any parameter so void in parameter list. We have assigned block literal at line number 4 which print "Hello,I am coding for bugs". We are calling block at line number 7.

In one shot we can declare block variable and assign block literals like this - 
 returnType (^blockVariableName)(parameterTypeList) = ^(parameterList){};

Following example shows that how to declare block variable and assign block literal in one shot -
    //this block calculate factorial of given number 
    NSInteger(^calculateFactorialOf)(NSInteger) = ^(NSInteger n){
        NSInteger fact = 1;
        if (n==0) {//factorial of 0 is 1 
            return fact;
        }
        for (int i=n; i>0; i--) {
            fact = fact*i;
        }
        
        return fact;
    };
    //call block, factorial will be assign to result 
    NSInteger result = calculateFactorialOf(4);
    NSLog(@"factorial = %i",result);//print 24
In above example you have seen how to use inline block and block variables.One main thing left about block is - it captures surrounding state that's why it is called as closures. Blocks are called closures because they are closed around variables that are in scope at the time of block declaration. Its means that a variable declare before of block declaration can be directly used in block.Block keeps a read only copy of in scope variables for example -
//calculate half of the given number using provided block and print the result 
-(void)calculateHalfOf:(NSInteger)number byExecutingBlock:(int(^)(int))block{
    NSLog(@"Half of %i = %i",number,block(number));
    //you can call block same as c functions 
    //syntax to call block using block name - blockName(commas separated parameter list)
    //like block(number); block1() and so on 
}

//cal the calculate method from viewDidLoad: method
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    NSInteger divider = 2;
    [self calculateHalfOf:4 byExecutingBlock:^(int n){return n/divider;}];
    //above block will carry a read only copy of divider variable 
}

OUTPUT:                                                                                                                            
     Half of 4 = 2                                                                                                                    

In above block we have not define the divider variable but we are using we can't modify the value of divider if we will do that it will give error as -


In above screenshot we can see that error - Variable is not assignable(missing __block type specifier).
Oh! Its not good, What will we do?if need to modify the divider variable. Don't worry take long breath and think what is __block? Yeah you are thinking right by using __block  storage type modifier we can make divider mutable.For example -
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
   __block NSInteger divider = 1;//__block makes variable mutable
    //see the above example for calculateHalfOf: byExecutingBlock: definition 
    [self calculateHalfOf:4 byExecutingBlock:^(int n){
        //modify divider, now it is not read only 
        divider = divider*2;
        return n/divider;}];
}
OUTPUT:                                                                                                                            
     Half of 4 = 2                                                                                                                    

When we use __block storage type modifier, variables passed by reference into the block.
Note: We should not use __block causally because it moves variables to heap, so please do not use it unless you really need it.
Hey cheers! We have completed basic of block programming.I can't believe that still you guys are reading! I salute your enthusiasm.Now i am going to discuss last things.
Declare block as property:

BlockDemo.h

#import<uikit/uikit.h>
typedef int (^devideEquallyBlock)(int);
@interface BlockDemo : UIViewController{
     devideEquallyBlock callbackBlock;
}
@property (nonatomic, copy) devideEquallyBlock callbackBlock;
-(void)calculateHalfOf:(NSInteger)number byExecutingBlock:(devideEquallyBlock)block;
@end
BlockDemo.m
#import "BlockDemo.h"

@implementation BlockDemo

@synthesize callbackBlock;

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

   __block NSInteger divider = 1;//__block makes variable mutable
    //assigning block to property 
    callbackBlock = ^(int n){
        divider = divider*2;
        return n/divider;};
    [self calculateHalfOf:4 byExecutingBlock:callbackBlock];
}
-(void)calculateHalfOf:(NSInteger)number byExecutingBlock:(devideEquallyBlock)block{
    NSLog(@"Half of %i = %i",number,block(number));
    //you can call block same as c functions 
    //syntax to call block using block name - blockName(commas separated parameter list)
    //like block(number); block1() and so on 
}
- (void)dealloc {
    [callbackBlock release];
    [super dealloc];
}
@end
In .h file i have used typedef, it is a c construct that assign a name to existing data type.For example i have given a new name devideEquallyBlock to block type "(int(^)(int))". Even Apple uses typedef to assign names to block because it keeps our code clean and readable.We should also use typedef.I have released block at line number 27 in .m file because i have called copy at time of property  declaration at line number 6 in .h file.

Thanks for reading, please leave your comments below,bye bye! 

1 comment:

  1. Nice tutorial with good explanation and enough stuff
    thank you so much Mithilesh

    ReplyDelete