Skip to main content

Blocks are Objective-C Objects !!!

Blocks

Blocks are executable code just like a function.  It can be written inside a function or we can store the reference in a variable and call it later.  But wait a minute these all functionality we can achieve by function pointer and functions. 

Then what is so special about blocks? Let first go through how we can define blocks.

 int (^sum)(int, int)  = ^(int number1, int number2){
        return number1+number2;
    };


The above block can be used to find the sum of two numbers.  If we recall the function pointer in c then it is very much similar to above:

int sumFunction(int number1, int number2){
    return number1+number2;
}
int (*sum) (int, int) = sumFunction; //Function Pointer *sum


Then Why we need Blocks if we already have Function pointer? 


1) Blocks can capture variables from the enclosing scope by simply referring to them within the block. How ? Let see the next Section
2)  Blocks are Objective-c Objects not like a  function pointer (reference to executable code). So Blocks stores much more information. What information ? Let see the next section
Any Other Difference !!!!

Yes there is one more point specially for technical Interview! block is define with (^) sign and function pointer with (*) :) .

Let's Check How Compiler Handles Blocks?

Like any other c code blocks also has two segment:

1) Code segment (text segment)
2) Data Segment (Block Literal)

Code segment:

Complied block code reside in different location not with in the code it actually define.


- (void) calculator{
    int (^sum) (int, int) = ^(int number1, int number2){
        return number1+number2;
    };
    int (^subtract)(int, int)  = ^(int number1, int number2){
        return number1-number2;
    };
}

In the above case calculator definition will reside at different location and "Sum and Subtract" definition will be at different place after compilation.


Data Segment (Block Literal):

We can see there is nothing special in code segment by which we can say blocks are different from the function and function pointer. So there is structure called Block Literal which make is special. The data structure store the information regarding the variable used from the outer scope and memory information regarding the blocks.

This data structure is generated by the Clang while compilation. So we do not need to worry about that. You just need to create a block and use it.

More Detail:

Blocks Stack To Heap Travel:

Blocks are objective-c objects. If you have gone through the above link you find in the block data structure   a member with name 'isa'. We already know with each object in objective-c we have this variable which used to find the class of the object.

Question is if Block is object then there must be a/are  class/classes for block?

Let find the class for blocks by run the following code:

NSDate *estDate = [NSDate date];
NSLog(@"%@",estDate);
void (^sum) (int number1, int number2) = ^(int number1, int number2){
     NSLog(@"sum is %@", estDate);
    
    };
NSLog(@"sum is of type %@", sum);
Output:
      sum is of type ;__NSMallocblock__0x7fd50863f850;

Now try the same code with ARC off or No.

Output:
      sum is of type ;__NSStackBlock__: 0x7fff560059e8;

Now try the following code:

void (^sum) (int number1, int number2) = ^(int number1, int number2){
        NSLog(@"sum is %d", number1+number2);
    
    };
    NSLog(@"sum is of type %@", sum);
Output:
sum is of type <__NSGlobalBlock__: 0x10256b0b0;

So now we have three different classes for block. Point is how to know  before run the code from which class my block belongs?

Class of a block is  depend upon the scope and memory segment in which it placed at run time:

1) NSMallocBlock
2) NSStackBlock
3) NSGlobalBlock

NSStackBlock:

Default when you create a block and Block Literal is placed on the stack and the class for the block is NSStackBlock. If you ever tried any objective-c object to placed on stack then it will give you the compilation error:

Just Try the following code:

NSString test = [[NSString alloc] init];
Error:
Interface type cannot be statically allocated

So blocks are different from the other objective-C object but still they are objective-c Object. Block also copy the local variable onto the stack which you have used from the surrounding scope. So Even if surrounding scope variable disposed after the function (capturing the block) is removed from the stack a copy of ivar is there in the stack for the block reference.

NSGlobalBlock:

In the above scenario if any block do not use the surrounding scope variable or object then clang configure it for the global scope. The class refer by the block is NSGlobalBlock. In the above example you can see if i am not using any surrounding Scope then in output it return NSGlobalBlock.

So block in this case is global and placed in global scope. So it will never be copied and disposed in this case.

NSMallocBlock:

We know one of the functionality given by Base class (NSObject) in Objective-c is methods for memory management (retain, copy, release).  Blocks are objective-c Object so these methods are also applicable on to the blocks.

When you copy a block which placed on the stack then a new memory is allocated on heap and all the code segment and data segment moved to the Heap. So new memory reference for all the block litreal member will be there when you copy a block from the stack to heap. Class denotes by block in this case is NSMallocBlock.

In case of ARC even if you define a block in a function it automatically has NSMallocBlock reference. i.e. ARC automatically send the copy message during compilation.

Memory points to take care(Be Safe):

Till know we are only talking about local variable is copied if used in a block. What happen if i refer any objective-C object in a block and the object disposed before the block called?

Answer is block retain the object when we send a copy message to a block. So the reference count of the object will increase when you copy the block. So we can use it without any harm. If we are giving any flexibility to a programmer then it come with the cost. Cost here is you need to take care of retain Cycle. How?

Retain Cycle:

typedef void (^ButtonTap)(id sender);

@interface EventHandling : NSObject 

@property (nonatomic, copy) ButtonTap tapEvent;

@end 

@implementation EventHandling

- (id)init {
    if ((self = [super init])) {

        self.tapEvent = ^(id sender){
                NSLog(@"object is %@", self); // self retain cycle
            };
    }
    return self;
}

- (void)dealloc {
    self.tapEvent = nil;
    NSLog (@"block free"); // never called.
    [super dealloc];
} 

@end 

In the above case TapEvent and Event Handling object never dealloc. As both retain each other.

Block Mysteries:


Stack Mystery (Non-ARC):

As we know block default created on a stack. So if you send a retain message to a block on stack(NSStackBlock) then it does not have any effect. Its reference count will not be increase. We already discussed Blocks can use variable from local scope. Let suppose if you are using an int variable from the function local variable and function is removed from the stack. Can we still have the same value in scaler variable ? Yes

All the variable used from the enclosing scope is const copy with in block data Structure (Block Literal).

Just Try to run the following code with Non-ARC:

    int numberSum = 0;
    NSLog(@"number sum address %p", &numberSum);
    void (^sum) (int number1, int number2) = ^(int number1, int number2){
         NSLog(@"number sum address %p", &numberSum);
    
    };
    sum(1, 2);
Output:    
    number sum address 0x7fff5a75e9cc
    number sum address 0x7fdb90ca6930 (Block on Stack)

Memory Address of the variable is changed.
Remember it is const copy you cannot change it. If you wanna change the value of variable just stay tune for next part of tutorial.

Heap Mystery:

You need to copy a block if you want to increase the scope or return a block from the method. When you send a copy message to a block then Block Literal also copied onto heap. Retain count of all the object used in block will also increase by one.

Just Try to run the following code with Non-ARC Environment:

    int numberSum = 0;
    NSLog(@"number sum address enclosing Scope %p", &numberSum);
    void (^sum) (int number1, int number2) = ^(int number1, int number2){
         NSLog(@"number sum address in block %p", &numberSum);

    };
    sum(1, 2);
    sum = [sum copy];
    sum(3, 4);
    sum = [sum copy];
    sum(5, 6);
Output:        
      number sum address enclosing Scope 0x7fff5ad15a0c
      number sum address in block 0x7fff5ad159f8 (Block  on Stack)
      number sum address in block 0x7fbe2b5c68e0 (Block on Heap)
      number sum address in block 0x7fbe2b5c68e0 (Block on Heap)


From the above result we can see if block is move from stack to heap then variable address is also changed. There is one more thing to notice when we send a copy message to block which is already on a heap then memory address is not changed.

Reason is when you send a copy message to a block on a heap then it will not allocate a new memory for the block it just increase the retain count of the block. It is optimization as scope of the block will not be change once it is created.

Pictorial View of Block Memory Allocation Cycle:


Execution Step 1:








Execution Step 2:





Execution Step 3:




Execution Step 4:


Comments

Popular posts from this blog

What does enable bitcode do in Xcode

Background: Now days compilation process for any language is divided into two parts and same is applicable for objective c. Frontend Compiler (Clang) Backend Compiler (LLVM) Frontend Compiler (Clang):  Responsibility of front-end compiler is to take a source code and convert into intermediate representation (IR).  In case of clang it is LLVM IR.  Backend Compiler(LLVM):  Responsibility of backend compiler is to take a IR as input and convert into object code. LLVM input is bitstream of LLVM IR (Bitcode) and output is sequence of machine instruction(Object code). Each  cpu or processor has different set of  M achine   instruction, So  LLVM output is CPU dependent or it can be executed on specific CPU only.   There may be question in your mind that  1) What is the need to divide into these phases? 2) What is LLVM IR? Can we see the LLVM IR as Output? What is the need to divide into these phases? It is beneficial for both the programming language designer a

Asynchronous Request with NSOperationQueue

Today post is about how to run a asynchronous task in NSOperationQueue.  Generally we do not run a Asynchronous task in NSOperationQueue. It is also not recommended for any programmer to do that. This post is only for learning purpose what will happen if we schedule a asynchronous task in a queue and how can we complete that task:). So let us move to the learning: NSOperationQueue: In iOS NSOperationQueue is a class, which provide a way to perform operation concurrently. We also have others way to perform concurrent operation: 1) GCD 2) NSThread 3) pThread NSOperationQueue is a wrapper on GCD, which provides a very convenient way to execute operation concurrently. To create a Queue for Operation you have to simply allocate a object of the class: NSOperationQueue * opertionQueue = [[ NSOperationQueue alloc ] init ]; For this post let suppose you are making a queue to handle all Http request in your application. So i want to create a queue in Handler class

Everything about BLE with iOS Part1 (Introduction)

In this article we will learn how to turn your iPhone to behave as peripheral (who has data to send) or central (who receive the data). What is BLE (Bluetooth Low energy device) ? Bluetooth LE is a wireless personal area network technology like its previous incarnation, Classic Bluetooth. It can be use to transfer and receiving of the data. What is difference between Classic and LE ? BLE has low power consumption and low data transfer rate. BLE can support large number of slaves. On the other hand Classic (3.0) support maximum 7 devices connectivity. Unique feature of BLE is advertising  functionality,  So other devices can scan,  connect and  receive data from the advertising BLE device. Other difference is in classic you need to pair the devices first for the communication. Terms: Peripheral:  It is device which advertise the service. In client-server architecture form we can say peripheral is server which has data to send to client. The basic difference i