Firstly, do this test on your knowledge of Blocks: Objc Blocks Quiz

What is block? Read a simple introduction here.

In short, it is a simple struct containing a function pointer! (It’s lambda in functional programming.)

A block is a reference-counted object, it contains the function-pointer invoke, which receives block itself as parameter. It also

There are 3 types of Blocks implementations in Objective-C: (you can use po debug-command to see type)

  1. NSGlobalBlock: a block doesn’t capture any variable from it’s scope (so it’s global). It resides in global memory. It is not Stack nor Heap block, it is like a normal function in the code.
    void (^aBlock)(NSString *someString) = ^(NSString *someString){
            NSLog(@"Block was executed. %@", someString);
        };
    NSDictionary *dictionary = [NSDictionary dictionaryWithObject:aBlock forKey:@"aBlock"];
    
  2. NSStackBlock: this block resides in stack memory.
    1. A normal block which access enclosing variables is created on stack. It means it can only be used within the scope of the enclosing function.
    2. A block which is defined inline to another function is created on stack.
  3. NSMallocBlock: this block resides in heap memory.
    1. A stack block when used with [copy] will be copied to heap. In heap it follows the reference-counting policy, and so will be released when there is no reference to it anymore.
    2. A block which access modifiable __block variable is in heap.

With ARC implementation, the way to define Stack or Malloc(Heap) Blocks have changed, so always use copy to ensure that the  block does not get out of scope and be released.

SYNTAX

Basically, a block is a wrapper of the C-style function pointer. It needs to be understood in 2 parts: the block declaration and the block type.

The Block declaration syntax is: ^(parameters) {}

The Block type syntax is: return_type (^block_name)(parameters)

blocks

MEMORY STRUCTURE

Screen Shot 2015-03-25 at 10.01.28 am

struct Block_literal_1 {
   	void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 {
		unsigned long int reserved;	// NULL
    	unsigned long int size;         // sizeof(struct Block_literal_1)
		// optional helper functions
   		void (*copy_helper)(void *dst, void *src);     // IFF (1<<25)
    	void (*dispose_helper)(void *src);             // IFF (1<<25)
   	    // required ABI.2010.3.16
       	const char *signature;                         // IFF (1<<30)
   	} *descriptor;
    // imported variables
};

All the captured variables are stored after the Descriptor region. All the objects will be copied, not physically but the pointers of them will be copied into the region below Descriptor struct.

BLOCK  TYPEDEF

Use typedef to make a long, complex block type simple and readable, also to hide the details from outsiders.

typedef return_type (^block_name)(parameters);

Example:

typedef int(^HAPBlock) (BOOL flag, int value);

Usage:

HAPBlock block = ^(BOOL f, int v) { … }

References:

  1. http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/
  2. https://www.mikeash.com/pyblog/friday-qa-2008-12-26.html
  3. http://ddeville.me/2013/02/block-debugging/
  4. http://clang.llvm.org/docs/Block-ABI-Apple.html#imported-const-copy-variables
  5. http://thirdcog.eu/pwcblocks/
Advertisements