Blocks

Understanding Blocks in iOS

Blocks are a powerful feature in iOS development that allow you to encapsulate a piece of code and pass it around as an object. They are a type of closure, which means they are self-contained blocks of code that can be passed around and executed at a later time.

Anatomy of a Block

Here is an example of a block in Objective-C:

int (^myBlock)(int) = ^ int (int parameter) {
    return parameter * 2;
};

This block takes an int parameter and returns an int. The block is assigned to a variable called myBlock. The block can be executed by calling the variable as if it were a function, like this:

int result = myBlock(3); // result is 6

Block Types

Blocks come in three different types:

  • Global blocks: These are created at compile time and are available throughout the application. They are not bound to any specific instance or context.
  • Stack blocks: These are created on the stack and are only available within the scope in which they are defined. They are automatically destroyed when the scope is exited.
  • Heap blocks: These are created on the heap and can be passed around and shared between different parts of the application. They are reference counted and are automatically destroyed when their reference count reaches zero.

Capture Lists

Blocks can capture variables from their surrounding context. When a block captures a variable, it creates a strong reference to that variable. This can cause retain cycles if not careful. To avoid retain cycles, you can use a capture list to specify which variables should be captured weakly or unowned.

Here is an example of a block with a capture list:

__weak typeof(self) weakSelf = self;

int myValue = 42;

void (^myBlock)(void) = ^{
    NSLog(@"%d and %@", myValue, weakSelf);
};

In this example, myBlock captures myValue and self weakly. This ensures that the block does not create a strong reference cycle.

Global Blocks

Global blocks are created at compile time and are available throughout the application. They can be used to define a piece of code that is used in multiple places in the application. Here is an example of a global block:

void (^myGlobalBlock)(void) = ^{
    NSLog(@"This is a global block");
};

This block takes no parameters and returns no value. It is defined at the top level of the file, outside of any function or method.

Stack Blocks

Stack blocks are created on the stack and are only available within the scope in which they are defined. They are automatically destroyed when the scope is exited. Here is an example of a stack block:

void myFunction() {
    int value = 42;

    void (^myStackBlock)(void) = ^{
        NSLog(@"The value is %d", value);
    };

    myStackBlock();
}

This block captures the variable value from the surrounding context and logs its value. The block is defined inside a function, and can only be used within that function.

Heap Blocks

Heap blocks are created on the heap and can be passed around and shared between different parts of the application. They are reference counted and are automatically destroyed when their reference count reaches zero. Here is an example of a heap block:

typedef void (^MyBlockType)(void);

- (void)myMethod {
    MyBlockType myHeapBlock = ^{
        NSLog(@"This is a heap block");
    };

    [self performBlock:myHeapBlock];
}

This block is defined inside a method and is stored in a variable called myHeapBlock. The block is then passed to another method called performBlock: which executes the block at a later time.

References