In iOS 4.3, there are 3 rather low level functions in the runtime that provide a new kind of bridge between Objective-C and Blocks with a specific goal of facilitating the dynamic generation of method implementations.

Specifically:

IMP imp_implementationWithBlock(void *block); void *imp_getBlock(IMP anImp); BOOL imp_removeBlock(IMP anImp);

In particular, imp_implementationWithBlock() takes a block as a parameter, copies it to the heap, and returns a trampoline that allows the block to be used as the implementation — the IMP — of a method in any Objective-C class (as long as the block’s arguments and the method’s arguments are compatible).

Quite literally, this allows:

int j = 12; IMP skewIMP = imp_implementationWithBlock(^(id _s, int k) { return k*j; });

Where skewIMP would then contain a function pointer that could be used as the IMP for a method declared like:

- (int)skew:(int)k;

Details on the flip side….Note that imp_implementationWithBlock() does not return a generic function pointer that can be used to call the block like a function. The key detail being that an IMP always has at least two arguments; (id self, SEL _cmd) .

To declare the Block, though, you drop the SEL _cmd argument while keeping the rest.

Like this:

-(void)doSomething: void(*doSomethingIMP)(id s, SEL _c); void(^doSomethingBLOCK)(id s); -(void)doSomethingWith:(int)x; void(*doSomethingWithIMP)(id s, SEL _c, int x); void(^doSomethingWithBLOCK)(id s, int x); -(int)doToThis:(NSString*)n withThat:(double)d; int(*doToThis_withThatIMP)(id s, SEL _c, NSString *n, double d); int(^doToThis_withThatBLOCK)(id s, NSString *n, double d);

The reason for this pattern has to do with the Objective-C and Blocks ABI. A method is really just a C function with two arguments at the beginning; the object being messaged and the selector of the method being executed. Similarly, a call to a Block is exactly like a C function with one argument at the beginning; a reference to the block (as described in the Block ABI on the llvm.org site).

As explained in the intimate tour of objc_msgSend() I wrote up a while ago, making objc_msgSend fast requires three optimizations and/or requirements:

Donâ€™t Mess With Registers (unless absolutely necessary)

Tail Call Optimized

Donâ€™t Mess with the Argument List

imp_implementationWithBlock() follows the same mantra; the returned function pointer is a tiny trampoline that does a minimally intrusive edit of the argument list and then tail calls into block’s implementation. Thus, it is fast and universally applicable to method implementations.

The key is that a method’s implementation always has two pointer sized arguments at the head of the argument list; (self & _cmd) . The trampoline overwrites the second argument ( _cmd ) with the first argument ( self ), then shoves the reference to the block into the first argument slot, and finally tail calls to the block’s implementation.

More importantly, the function pointer — the IMP — returned by imp_implementationWithBlock() is an IMP like any other. It can be passed to any IMP taking API and the type string passed to class_addMethod() is unchanged from a regular “compile time IMP”.

End result?

The block is invoked with self being the first parameter to the block and, most importantly to the sanity of the engineers who wrote this (and for performance reasons), all other arguments, from none to many, are left entirely untouched in the process.

The other two functions — imp_getBlock() and imp_removeBlock() — are provided for completeness’s sake. Obviously, removing and destroying a block that is currently the IMP of a method is a great way to create a “quick quit” easter egg in your application.

Putting it Together



Using Xcode 4.0 and iOS 4.3, create a new iOS View Based Application.

Replace the code in the provided main.m with the following:

#import <UIKit/UIKit.h> #import <objc/runtime.h> @interface Answerer:NSObject @end @interface Answerer(DynamicallyProvidedMethod) - (int)answerForThis:(int)a andThat:(int)b; - (void)boogityBoo:(float)c; @end @implementation Answerer @end int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int (^impyBlock)(id, int, int) = ^(id _self, int a, int b) { return a+b; }; // grab an instance of the class we'll modify next Answerer *a = [Answerer new]; // create an IMP from the block int (*impyFunct)(id, SEL, int, int) = (void*) imp_implementationWithBlock(impyBlock); // call the block, call the imp. Note the argumentation differences NSLog(@"impyBlock: %d + %d = %d", 20, 22, impyBlock(nil, 20, 22)); NSLog(@"impyFunct: %d + %d = %d", 20, 22, impyFunct(nil, NULL, 20, 22)); // dynamically add the method to the class, then invoke it on the previously // created instance (or we could create the instance after adding, doesn't matter) class_addMethod([Answerer class], @selector(answerForThis:andThat:), (IMP)impyFunct, "i@:ii"); NSLog(@"Method: %d + %d = %d", 20, 22, [a answerForThis:20 andThat:22]); // It is just a block; grab some state (the selector & a variable) SEL _sel = @selector(boogityBoo:); float k = 5.0; IMP boo = imp_implementationWithBlock(^(id _self, float c) { NSLog(@"Executing [%@ -%@%f] %f", [_self class], NSStringFromSelector(_sel), c, c * k); class_addMethod([Answerer class], _sel, boo, "v@:f"); // call the method [a boogityBoo:3.1415]; // clean up [a release]; [pool release]; return 0; }

And the output:

ImpityImp[2298:207] impyBlock: 20 + 22 = 42 ImpityImp[2298:207] impyFunct: 20 + 22 = 42 ImpityImp[2298:207] Method: 20 + 22 = 42 ImpityImp[2298:207] Executing [Answerer -boogityBoo:3.141500] 15.707500

: link_pages issince version 2.1.0! Use wp_link_pages() instead. inon line