Blocks in Objective-C
Based on my "Introduction to Blocks" lightning talk.
I gave a quick introductory talk about blocks in Objective-C for iOS and Mac development tonight, and I thought I would put together some of the slides and my notes here as a post.
The least you need to know
Blocks are like closures. Or function pointers. Or lambdas. They’re available starting in OS X 10.6 Snow Leopard and iOS 4.
The symbol for blocks is this: ^
That’s a reasonable ASCII approximation of the real Greek lambda (upper case Λ, lower case λ).
Here’s a really simple block, the requisite “Hello world”:
^{ NSLog(@"Hello, world!"); };
Of course, that won’t actually do anything; it’s like declaring a function and not calling it. So here’s the revised version:
void (^myBlock)() = ^{
NSLog(@"Hello, world!");
};
myBlock();
Block declarations look very much like function pointers, if you have dealt with those in C. In our example here:
void
is the return type- ^ indicates it’s a block
myBlock
is the name of the variable- the () means it doesn’t take any arguments; we could also write
(void)
- note that blocks are C statements, so the closing brace is followed by a semicolon.
Blocks for enumeration
Here’s our case study, a classic map (as in map/reduce): we have an array of a million objects. We need to iterate through the array and do some work for each array element.
We could use a for loop or NSEnumerator. In the more recent runtime, we might use fast enumeration like so:
NSArray *collection = [[NSArray alloc] ...];
for (id object in collection) {
// do something here
}
Here’s the block way of doing it. We put the block code directly inline, although you can set up a block variable in advance if you like:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// do something
}];
For the block function’s arguments:
obj
is the value from the arrayidx
is the array index*stop
is used if you need to exit early; set*stop
toYES
to break out of the loop/iteration
Concurrency
Blocks are a natural gateway to Grand Central Dispatch (GCD) and being able to take advantage of parallelism, whether through multi-cores, multi-processors, or multi-threads. If it’s OK to iterate through the collection in parallel and out of order:
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// do something
}];
So there’s nothing about blocks themselves that speeds up your code. What they offer is a very easy way to segment bits of hard-working code and then lean on GCD to handle the dispatching.
Further reading
There are a lot of topics such as block variables and memory management that are explained far better and in more detail than I could provide. Here are some links: