With the release of OS X 10.6 Snow Leopard Apple gave programmers some of the most powerful tools yet for Objective-C programming: Blocks, with the magnificent Grand Central Dispatch library built on top of them.

If you need to learn the basics of Objective-C, We have a great Beginners Guide to Objective-C Tutorial, check it out.

The more advanced programmers among you might know the concept already: technically they are called closures, and were first introduced in the Scheme language in the early 1970’s. Many languages since then have had support for them in one form or another, including Smalltalk, Objective-C’s message-oriented inspiration, Ruby, and even the new C++0x standard has a form of support, albeit without the real ‘closure’ part. The term closure itself refers to the most alluring behaviour of this feature: a block of code, defined inline, takes the current values of any local variables in the same scope and keeps hold of them. This means that you can refer to values determined at runtime from within a closure block without needing to explicitly copy them yourself. Note that C++0x lambda functions don’t implement this particular feature, however.

One very useful benefit of Objective-C blocks/closures, as anyone who’s ever written code in such a language will tell you, is that they can give you a very neat and tidy way of implementing concurrent code. Specifically, thread-safe concurrent code without locks. This is all based upon the use of serial queues; yes, not unlike an NSOperationQueue with its maximum concurrency set to 1. You can already use a queue like that of course, but it’s a little more awkward to actually put tasks onto that queue. Objective-C Blocks give us the ability to implement a much simpler way of doing the same thing. For instance, take the following code:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void) setTitle: (NSString *) newTitle
{
    @synchronized(self)
    {
        [newTitle copy];
        [myTitle release];
        myTitle = title;
    }
}

- (NSString *) title
{
    NSString * result = nil;
    @synchronized(self)
    {
        result = [myTitle retain];
    }
    return ( [result autorelease] );
}

Those methods behave in much the same manner as the synthesized accessors for an atomic, copied property. To implement atomicity, they use a lock (the real property code doesn’t actually use @synchronized, it uses a more optimized set of locks; the principle is the same, however). The ‘problem’ with this code is that it always acquires a lock— even if it doesn’t need to. This causes a lot of overhead, such that if this property were accessed or changed frequently you would probably want to optimize them. In order of decreasing cost, you could use NSLock, pthread_mutex, pthread_rwlock, or OSSpinLock. If those weren’t fast enough, you could do some clever math on the values to implement a non-locking algorithm. But that can be a pain to write efficiently (or indeed at all). This is where queues come in, and where blocks make these queues wonderfully simple to use. Here’s what you could write, given the existence of a single global serial queue upon which to run your blocks:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void) setTitle: (NSString *) newTitle
{
    [mySerialQueue runBlockSync: ^{
        [newTitle copy];
        [myTitle release];
        myTitle = newTitle;
    }];
}

- (NSString *) title
{
    __block NSString * result = nil;
    [mySerialQueue runBlockSync: ^{
        result = [myTitle retain];
    }];
   
    return ( [result autorelease] );
}

Each of the blocks in the above two methods takes no parameters and returns no values; they just operate on their current scope. However, they don’t have any locks. They achieve thread-safety by performing their duties on a serial queue— and it’s this queue which provides the thread safety. By its serial nature, no matter how many threads step through the code above at any one time, the queue will run each block in the order it was received, one at a time. So no setter and no getter will *ever* preempt another.

Also note that these are being run synchronously— this ensures that the API contract is enforced for the setters (the new value will have been set by the time the setter function returns), and that the block can modify a stack variable to be returned in the getter. If such contracts aren’t needed, you could just as easily drop the new value into a queue to be run asynchronously, and return safe in the knowledge that while it might not have been set right now, it will be set at some point in the future, and still in order respective of other threads calling this API.

As for the -runBlockSync: on NSOperationQueue seen above, you could implement such a function with this code I just whipped off in a completely random and untested fashion:


1
2
3
4
5
6
7
8
9
10
11
12
13
@interface NSOperationQueue (AQSyncBlockSupport)
- (void) runBlockSync: (void (^)(void)) block;
@end

@interface NSOperationQueue (AQSyncBlockSupport)

- (void) runBlockSync: (void (^)(void)) block
{
    NSOperation * operation = [NSBlockOperation blockOperationWithBlock: block];
    [self addOperations: [NSArray arrayWithObject: operation] waitUntilFinished: YES];
}

@end

Blocks Internals

Objective-C Blocks are quite special constructs. The chief reason for this is their ability to capture the lexical scope in which they were defined, keeping the values of variables defined on the stack preserved with them. While this is very powerful, it leads to some questions of memory management, and therefore some new rules to learn. Thus we’ll now look at a block’s life-cycle.

Blocks start out on the stack

All Objective-C blocks are initially created on the stack. If they aren’t kept around anywhere, for instance if they’re only passed into synchronous API, then they will remain there for their entire lifetime, and will simply go away when their stack frame returns. While stack-based, a block has no effect on the storage or lifetime of anything it accesses.

Blocks can be copied to the heap

If you want to keep a block around, it can be copied to the heap. This is an explicit operation, which will not happen for you. As a result of being copied to the heap, a block will gain proper reference-counting in the manner of all Objective-C or CoreFoundation objects. When they are first copied, they take their captured scope with them, retaining any objects as necessary to keep them around.

Blocks have their own private const copies of stack variables

If a block references a stack variable, then when the block is initialized it is given its own copy of that variable, with one twist: the copied variable is declared const. This means that you cannot change the values of referenced variables directly from inside your blocks (without a little extra sauce at least: see below for the details). However pointer types remain pointers: you cannot assign a new address value to a pointer, but the value it points to can still be modified. This applies to Objective-C objects, so these can be modified directly. For CoreFoundation types, note that the typedefs for most of those with mutable and immutable variants define those types as [type] * and const [type] * respectively, so your CFMutableStringRefs and CFMutableArrayRefs will cease to be mutable from within your blocks unless you type-cast them.

Mutable stack variables must be declared with the __block keyword

If you have an integer counter which must be modified by the code in a block, then you will need to declare it as __block int x rather than just int x. Doing so will make the compiler arrange for it to be placed on the heap so that it can be used by all blocks, and will no longer be declared const inside the block itself. Another effect is that any Objective-C objects declared in this way will not be sent a -retain message. Another side-effect is that the variable will be shared by all blocks which access it, so modifications made by one block will be seen by another— they will not have their own mutable copies of the variable’s initial value. This also applies to the stack frame containing that variable, so modifications made later in that stack frame will also be visible to your blocks

Globals ‘just work’

Globals are globals. They exist once in memory, whether it be on the heap or in the mutable data segment of a binary file. Blocks don’t need to do anything special with them, and blocks accessing them from different threads concurrently still need to synchronize their access to them, just like everything else.

How does it work?

Imagine we have a simple function which uses a block, passing it to a hypothetical repeat() function, which takes an iteration count and a block to perform. Our simple function is written like this:


1
2
3
4
5
6
7
8
void doSomething( void )
{
    int local = 1;
    __block int shared = 0;
    repeat( 20, ^{
        shared += local;
    });
}

When this function is called, its stack frame will look something like this:

A block, with a __block variable, as it initially appears on the stack.

You can see that the chunk of memory for the block includes a new const int variable— this is the const copy of the stack’s local variable. It does not have a copy of the shared variable from the stack, since that was declared using the __block storage specifier.

If the block is never copied, then nothing here changes. Once the block is copied, however, a copy of the block is created on the heap, and the __block variable it references is moved to the heap. Your memory now looks something like this:

The same block after it has been copied to the heap.

Two copies of the block now exist, each with their own const copy of the local variable. The shared variable still exists in one place, but that place has now moved from the stack to the heap. Variables moved to the heap in this way have a reference count, and are retained by each copy of a block which references them. In this case the shared variable has a retain count of 2: one for the stack-based block, and one for the heap-based block.

If the stack unrolls, the block there will release its reference on the shared variable automatically, leaving it with a reference count of 1. Likewise if the heap-based block is deallocated first, it will do the same, again leaving the shared variable with a reference count of 1. When both blocks have been deallocated, the shared variable will also be released.

Objects and __block

For the most part, you won’t ever need to worry about storage classes for Objective-C objects themselves. They are pointers to memory allocated on the heap, so your blocks will be able to use them automatically. When a block is copied, the runtime magic will retain any Objective-C types (which also includes CoreFoundation types thanks to a little of the deep magic in the guts of the Foundation framework) automatically, and it will release them when the block is deallocated.

The only time you’ll need to use the __block storage specifier for an ObjC type is when you want to assign it a value directly. For comparison, look at the two statements inside the following block:


1
2
3
4
5
id object = ...;
repeat( [object count], ^{
    [object setValue: @"hello" forKey: @"greeting"]; // ok
    object = [object nextObject];                    // error
});

The first statement is fine. Even though it is modifying the object, it’s not modifying the value of object; that still contains the address of the object on the heap. The second statement however actually modifies that value, making it point to another object, and that falls foul of the copied variable’s new const declaration. To make this work, we use __block like so:


1
2
3
4
5
__block id object = ...;
repeat( [object count], ^{
    [object setValue: @"hello" forKey: @"greeting"]; // ok
    object = [object nextObject];                    // ok
});

Block memory management

The Blocks runtime includes support for both the C and Objective-C languages. Blocks are implemented in such a way that they are also first-class citizens in the Objective-C runtime: they all have an ‘isa’ pointer which defines a class through which the Objective-C runtime can access methods and storage. The block objects don’t implement everything that you might want to use however; they implement only the -copy, -release and -autorelease methods. They also implement -retain in order to play nicely with collections, but you should always use -copy instead. Why? Because a stack-based object will not be copied to the heap if you send it a -retain message; it will only be copied upon receipt of the -copy message.

The C variants of these functions provided by the Blocks runtime are Block_copy() and Block_release(). These work in a similar manner to their Objective-C counterparts with the exception that these must occur in matched pairs. As such, it is highly recommended that you use the Objective-C methods instead of these wherever possible.

That’s it for today— you now know what Objective-C blocks are and how they work. In a future article I’ll describe some more of the concrete tasks you can perform using Objective-C blocks, and will provide an introduction to Grand Central Dispatch.

Problems?

We have a new Questions and Answers section so you can get help from the awesome community.

Ask a Question

Enjoyed this post?

Subscribe to our RSS Feed or Follow us on twitter to keep up to date with the latest from iOS-Blog. Remember, Sharing is caring so please click one of the following options:

Tags: , , ,