2013-02-28 08:08:02 Recursive block macro
There was some fine detective work by Jeremy Sherman on exactly how to prevent leaks when creating recursive blocks in an ARC environment. The solution, however, is wordy. This isn't his fault of course, it's fallout from the combination of blocks syntax and ARC memory management. But it was cumbersome enough for me to design a custom wrapper for it in the form of a C macro. I made the argument order the same as how you'd write a traditional block, but feel free to make it more your own style. Perhaps a handy Xcode snippet.

( objc )
  1  #import <Foundation/Foundation.h>
2
3 #define recursiveBlock(type_out__, name__, type_in__, block__) \
4 typedef type_out__ (^type_in_out__##name__)type_in__;\
5 __weak __block type_in_out__##name__ name__;\
6 type_in_out__##name__ temp__##name__;\
7 name__ = temp__##name__ = ^type_out__(type_in__) block__
8
9 int main() {
10
11 recursiveBlock( int, factorial, (int a), {
12 if (a<2) return 1;
13 else return a * factorial(a-1);
14 });
15
16 NSLog( @"5! = %i", factorial(5) );
17
18 recursiveBlock( int, exponent, (int a, int b), {
19 if (b<1) return 1;
20 else return a * exponent( a, b-1 );
21 });
22
23 NSLog( @"3 ^ 7 = %i", exponent( 3, 7 ) );
24 }

You have to put the input type information in parenthesis, and you have to name the variables that you intend to use, so it's perhaps odd seeming. The parentheses are so that if you have multiple arguments you're all set. Note also that when making use of the macro, you do not have to deal with redundant type information when writing this quasi-literal statement. Also note that there is no carrot when writing your block! This may obscure the fact that you are even dealing with blocks, but I think overall it's a net win.

Edit: Important oversight caught by Edward Patel involving multiple uses of the macro. Many thanks!
Leave a comment