Saturday 29 November 2014

iOS Swift Closures and Objective C Blocks

Blocks/Closures are fragment of code that can be executed along-with/in-between another section of code, by passing them to those sections through method arguments/variables/properties. There the Blocks/Closures will be executed as next line of code from where they are invoked. Blocks can return like normal methods

Example 1:

How to create a block/closure ?

1) Define Block/Closure data type

// create types globally
Objective C Syntax: typedef returnType (^blockname>)(arguments);
typedef void(^DisplayMessage)(NSString *message);

Swift Syntax: typealias blockname = (arguments) -> returnType

typealias DisplayMessage = (message:NSString) -> Void

2) Create method with block/closure as parameter and Invoke the block ( invoking inside method body itself is Optional and not mandatory. Also it can be set/hold in a property and invoked later on)

Objective C:

-(void)displayMessageWithHandler:(DisplayMessage)handler
{
    handler(@" The execution of block of code started "); // block of code invoked
}

Swift :

func displayMessageWithHandler(handler:DisplayMessage) -> Void
{
    handler(message: " The execution of block of code started "// block of code invoked
}

3) Invoke the method

Objective C:

[self displayMessageWithHandler:^(NSString *message) 

// block starts 

        NSLog(@"%@",message); // displays " The execution of block of code started "
        
        // fragments of code written here will be executed ...

        // statement n 
        // statement n+1 
        // ......

// block ends
}];

Swift :

self.displayMessageWithHandler 
{ (message) -> Void in
          
// closure starts

        println(message)

        // fragments of code written here will be executed ...

        // statement n 
        // statement n+1 
        // ......

// closure ends

}

Features:

Some of the features of Blocks/Closure are similar to the function pointer in C++. In iOS Blocks/Closures are treated as Objects. Hence they can be retained, released and even added to NSArray and NSDictionary

In Swift Closures are alternatives of Objective C Blocks. Blocks are known by name Closures in other programming languages too

The Advantage of using Blocks OR Closures are
  1. Alternative technique to delegate/callback
  2. Executable piece of code can be passed to a method/other sections and executed there
  3. Blocks along with Grand Central Dispatch (GCD) are one of the best and faster solutions for Multithreaded Web Service Access/ API integration designing [ (3) this will be explained with the help of an Example code in a separate post ]
Example 2:

This is a Simple sample code that demonstrates how blocks/closures can be passed and executed. Here blocks/closures acts as a sole decision maker of Bubble Sort implemented in a method body. Here blocks returns a BOOL type

1) Create block/closure types

Objective C:

typedef BOOL(^CompareBlock)(NSNumber *number1,NSNumber *number2);

Swift :

typealias CompareBlock = (number1:NSNumber, number2:NSNumber) -> Bool

2) Creating Category/Swift-Extension for NSMutableArray to implement sorting

Objective C:


@implementation NSMutableArray (sortArrayCategory)

-(NSMutableArray*)sortListWithSortHandler:(CompareBlock)compare
{
    /* Bubble Sorting */
    for(int j = 0; j < (self.count - 1); j++)
    {
        for(int i = 0; i < (self.count - 1); i++)
        {
            if(compare(self[i],self[i+1])) // Calling the block = Executing the piece/block of code
            {
                [self exchangeObjectAtIndex:i withObjectAtIndex:i+1];
            }
        }
    }
    
    return self;
}

@end

Swift :


extension NSMutableArray /* Category in Objective C */
{
    func sortListWithSortHandler(compare:CompareBlock) -> NSMutableArray
    {
        /* Bubble Sorting */
        for(var j = 0; j < (self.count - 1); j++)
        {
            for(var i = 0; i < (self.count - 1); i++)
            {
                if compare(number1: self[i] as NSNumber,number2: self[i+1as NSNumber/* Calling the Closure = Executing the piece/block of code /*
                {
                    self.exchangeObjectAtIndex(i, withObjectAtIndex: i+1)
                }
            }
        }
        
        return self
    }
}

3) Create Array with list of numbers and Call the Category method

Objective C:

NSMutableArray *numberList =       [NSMutableArray arrayWithObjects:@300,@100,@1000,@500,@200,@100,@2000,@4000,@2300nil];
    
[numberList sortListWithSortHandler:^BOOL(NSNumber *number1, NSNumber *number2) 
{
        
        /* This block of code decides the type of sort Ascending OR Descending. It plays the role in making comparison for Bubble sort. Ascending if '>' and Descending if '<' is used */
        
        return (number1.integerValue < number2.integerValue);
        
}];

Swift :


var arrayList:NSMutableArray = [ 1200200340050008001009900]

arrayList .sortListWithSortHandler { (number1, number2) -> Bool in
            
            /* This enclosed Closure decides the type of sort Ascending OR Descending. It plays the role in making comparison for Bubble sort. Ascending if '>' and Descending if '<' is used */

        return (number1.integerValue < number2.integerValue)
}

Variable and Method accessibility in Blocks/Closures:

Inside blocks : Global variables , Global methods, Local variables inside method scope and imported constants can be referred. Among the variables only global variables are mutable by default. We need to make local variable mutable using keyword __block before the variable. It is recommended not to use the Mutable Arrays of __block type

Example 3:

__block int count = 100


[self sampleBlock:^(......) 
     count = count++; // No error. Hence variable can be mutated
}];

Blocks/Closures and Memory management
  • Copying blocks creates strong reference to object variables used within the blocks
  • If Instance variables that are out of block's scope are used inside the block, those variables are strongly referenced by default
Blocks/Closures Uses and Possibilities
  • Simultaneous enumeration and iteration through Collections
  • Web Service / API access : Success and Failure Completion handlers - ( best if used along with GCD )
  • As Callbacks
  • Blocks can return another block
  • Blocks can have another block as parameter
  • Nested blocks is possible. But has to be implemented with great care ! developer needs to avoid memory leaks / retain cycles / reference related problems
  • Blocks can be added to Array. Here also developer needs to avoid memory leaks / retain cycles / reference related problems