Objective-C Blocks

Lately, I have been playing with Objective-C blocks.

These are easy to use constructs that enable defining functions “on the fly” when programming in Objective-C and are very similar to Python’s lambdas.

The syntax might look a little weird at first, but it is not that different from working with function pointers in C.

Here’s a simple example of a function f that receives a block b as a parameter and calls it. The only restriction imposed on b by f is that it must be a block that takes an int argument and returns an int.

#include <stdio.h>

// f is a function that receives a block:
void f(int (^b)(int))
{
	b(0); //call the block
}

int main(int argc, char* argv[])
{
	// Define and pass a block to f():
	f(^(int p){ printf("%d\n", p); return 0; });

	return 0;
}

The output of this program is just the int supplied by f to the block b.

Let’s try a more interesting example. Here, as inspired by this post, we use blocks to define a general-purpose for_each function that receives a list of objects and a block and then applies the block on each element of the list.

In order to define a general-purpose for_each function, we take advantage of Objective-C’s dynamic typing and name our types id.

void for_each(NSArray* array, void (^b)(id))
{
	for (id obj in array)
	{
		b(obj);
	}
}

Now, let’s develop a short program to test the for_each. This program creates a list of strings and uses the for_each function to output all of its contents.

int main(int argc, char* argv[])
{
	// Default autorelease pool:
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
	
	// Create an array. The contents could be anything,
	// as long as the block can handle them:
	NSArray* array = 
	[NSArray arrayWithObjects:@"a", @"b", @"c", @"d", @"e", nil];

	// Print every string instance:
	for_each(array, 
		^(id str){ printf("%s\n", [str UTF8String]); });

	[pool release];
	
	return 0;
}

Suppose now that we wanted to print out strings in uppercase. No problem, we can keep all the same structure, we just need to change the block:

	for_each(array, 
		^(id str){ 
			printf("%s\n", [[str uppercaseString] UTF8String]); 
		});

So, what happens if we place an object of a type different from a NSString instance in the array? Well, the for_each is very general and doesn’t know anything about the array’s elements or the block’s internals. Thus, if there is a problem, it will be triggered inside the block code.

Imagine we attempt to send uppercaseString to an object that does not recognize that message. If this happens, an error will be triggered at runtime and abort() will be called, canceling our program.

As we move into dynamic coding, the code becomes more flexible, but we must be more careful not to trigger runtime errors in our programs. It’s important that we develop our blocks to be consistent with our data structures.