iOS and Objective-C block quickref

Published December 08, 2010

This is a reference/cheat sheet of Objective-C blocks, introduced in iOS 4.0 and OS X Snow Leopard.

I keep forgetting the syntax, especially for writing methods that takes blocks. I hope you'll find this quickref useful, I certainly will.

Passing blocks

// The very simplest case.
[foo someMethod:^{
    // Any code here.  
}];

// A block that takes arguments.
[foo someMethod:^(NSString *something, BOOL somethingElse) {
    // something an somethingElse can be used just like function arguments.
}];

Taking blocks

// Take a block with no arguments
- (void)someMethod:(void(^)())block;

// Take a block with arguments
- (void)someMethod:(void(^)(NSString *test, id anyObject))block;

// Any return type is OK.
- (void)someMethod:(BOOL(^)())block;
- (void)someMethod:(NSRange *(^)())block;

// Call a block
- (void)someMethod:(void(^)(NSString *test))block {
    block(@"Yep");
}

The syntax can be described as:

a(^)(b);
a = Return type
b = Arguments

DRY block signatures

You can create a type for your block signature, if you're using the same signature many places.

typedef BOOL (^MyCustomBlock)(NSString *something);

- (void)myMethod:(MyCustomBlock)block {
    BOOL result = block(@"whatever");
}

[foo myMethod:^(NSString *string){
    return [string isEqualToString:@"give you up"]
}];

Inferring return type

The compiler will infer the return type of a block for unspecified return types, making return type specification optional. In the examples above, we have never specified the return type. This is how block creation looks with an explicit return type.

[foo someMethod:BOOL^{ return YES; }];

// Inferred return type, for good measure.
[foo someMethod:^{ return YES; }];

Using blocks returned from methods

This actually have a use case; storing blocks in a NSArray or similar.

// Assuming "callbacks" is an NSMutableArray instance variable.
- (void)registerCallback:(BOOL(^)())callback {
    [_listeners addObject:[[callback copy] autorelease]];
}

- (void)runCallbacks {
    int i = [_listeners count];
    while (i--) {
        BOOL (^block)() = [_listeners objectAtIndex:i];
        BOOL state = block();
        // And so on...
    }
}

As we can see, the return type isn't inferrable in this case.

The reason for copying the block in registerCallback: is that the block can be (and most likely is) on the stack when we get it. Copying it moves it to the heap.

Recommended reads


Questions or comments?

Feel free to contact me on Twitter, @augustl, or e-mail me at august@augustl.com.