Blocks, An Introduction

Introduction:

Blocks in Obj-C, are literally ‘blocks’ of code and they works coherently with GCD(Grand Central Dispatch), a subsystem in Cocoa and Cocoa Touch frameworks to concurrently pass commands, using queues, either synchronously or asynchronously.

Blocks implement ‘Command Design Pattern’. Before going into the details of blocks, lets see an analogy , or to put it better, its roots in C programming. To better understand, check this article.

Refresher on Pointers in C:

Pointer reference:

A pointer variable of any data type can hold a reference to that data in memory, and the value of the pointer is just the address of referenced data. Although pointer values, the address doesn’t differ between the data type and the size is the same across the device, it is important to specify pointer type for purposes of ‘Address arithmetic’.

//declare integer pointer
int *integerPointer;
int integerVariable=10;

Pointer de-reference:

To access values stored in the pointer, it has to be de-referenced, which returns the data stored in that memory address.

//assign pointer 
integerPointer = &integerVariable;
//printing memory address of integerPointer
printf("%p\n",integerPointer);
//de-referencing pointer
printf("%d\n",*integerVariable);
//output:
0x7fff5fbff7cc
10

Pointers to functions:

Just as data pointers can hold memory address of valid data types, address of functions can be assigned to pointers with the correct signature.  However, pointers  can be cast if needed.

Below code illustrates, use of pointers to functions.

#import <stdio.h>
#import <stdlib.h>
//function declaration,which takes two int parameters and returns and int
int* functionName(int*,int*);
//function pointer declaration
//a pointer to a function, which takes two int parameters and returns and int
int* (*functionPointer)(int*,int*);
//another pointer to a function to which takes two int and returns a void
void (*functionPointerToCast)(int*,int*);
// function implementation
int* functionName(int* first,int* second)
{
    if (*first > *second) {
        ++(*first);
        return first;
    }else
    {
        ++(*second);
        return second;
    }
    // 	returning largest reference after increment
}
int main(int argc, char* const argv[])
{
    int one,two;
    one=1,two=2;
    //pointer, points to the function of the same signature(takes two int parameters and returns an int)
    functionPointer = functionName;
    //if the signature is not the same, then cast pointer
    functionPointerToCast = (void(*)(int*,int*))functionName;
    //calling function
    printf("Returned sum is %d\n",*(functionName(&one,&two)));
    //de-referencing function pointer and calling
    printf("Returned sum from pointer is %d\n",*((*functionPointer)(&one,&two)));
    // de-referencing cast function pointer and calling
    (*functionPointerToCast)(&one,&two);
    return 0;
}

Blocks:

Before looking at the details of using blocks; Some benefits are:

  1. Callbacks – a block is passed mostly as an argument and this block will be called back.
  2. Concurrency – along with GCD, blocks are passed to queues synchronously or asynchronously for instance, download a network resource in background.
  3. Delegates – Apart from conventional delegation, where the delegate implements a delegate protocol, blocks can be passed as delegates, which are called back.
  4. First class objects – Although created in the stack, blocks are anonymous objects, which can be stored in the heap, have a reference and its as any other objects.
  5. Capture scope and __block storage class – Data in variable within the same scope as the block can be access within the block, but read-only. This is because it is passed in by-value. To modify data inside the block, the variable passed in must be specified with __block storage class, so the passed data is now passed by-reference. Data modified within the block is retained outside the block.

Blocks has the same syntax as function pointers.

To use blocks, follow these steps:

1.Block declaration

Here the signature of the block is declared. Lets see each of the parts in the signature.

(^blockName) – this is the name of the block, just like pointer to a function.

<returnType> – return type from the block – optional.

(dataType1,dataType2) – input parameters which the block takes.

For convenience, block signature is typdef-ed for easy reference, by creating variable of block type, or else the whole signature has to be used to assign the block, this can get a bit confusing, as a best-practice, typedef the block signature and use the variable for assignment.

//block declaration 
<returnType>(^blockName)(dataType1,dataType2);
//typedef declaration
typedef <returntype>(^blockName)(dataType1,dataType2);
//block variable declaration
blockName blockVariable;

2.Block creation

Once the block signature is declared, and variable created. A block body with this signature can be created and assigned.

//blocky creation
^returnType(datatype1 parameter1,dataType2 parameter2)
{
//block content
return returnType;
};

Breaking down the steps

^ – a block body begins with the carat sign

returnType – optional, it can be implied from the returned in the block body

datatype1 parameter1,dataType2 parameter2 – input parameters

return returnType – returned data from the block

3.Block assignment

After creating the block body, its simply assigned to the block reference created earlier.

4.Block calling

Using the block reference, or the block name, it can be called directly after creation or passed to another method or function and called back, the latter is commonly used in framework methods and for delegates.

#import <stdio.h>
#import <stdlib.h>
typedef void(^blockName)(int,int);
blockName blockVariable;
//function accepting a block
void functionWithBlock(blockName);
// function implementation with block
void functionWithBlock(blockName blocks)
{
//    calling back the block
    blocks(25,50);
}
int main(int argc, char* const argv[])
{
    
    blockVariable = ^void(int first, int second){
        printf("Input parameters in the block %d, %d \n",first,second);
    };
//    block call
    blockVariable(100,200);
//    passing the block to a function
    functionWithBlock(blockVariable);
    
    
    return 0;
}

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *