Objective-C Blocks, Recursion Errors

Guys,

I am trying to execute a function that calls itself, but by putting everything in one block,

As you can see, the following function is intended to be called an indefinite number of times (until the arcrandom returns a number below 50), and you should expect the message number to be β€œRUNNING” as the output of the variable, depending on the probability.

void (^_test_closure)(void) = ^ { NSLog(@"RUNNING"); if(arc4random() % 100 > 50) { _test_closure(); } }; _test_closure(); 

However, when I start, I get the EXC_BAD_ACCESS error, and the reason I found is that when the code tries to call _test_closure inside the closure, it basically points to nowhere.

Does anyone know how to make the above code work?

+7
source share
3 answers

Recursion and blocks are complex. Since the block captures all the passed variables, the _test_closure variable is not yet initialized (and clang should give you a warning:

Block pointer variable '_test_closure' is not initialized when captured by the block

)

There are several ways to get around this, but the most obvious and easiest is to simply make the __block variable block itself (as @ H2CO3 said). This allows the block to be weak-linked almost, so when you call it again, it initializes correctly.

Another option you have is making the block global or static, for example:

 // outside of 'main', thus being a global variable void (^blockRecurse)(int) = ^(int level) { if (level < 0) return; NSLog(@"Level: %i", level); blockRecurse(--level); }; int main() { @autoreleasepool { blockRecurse(10); } } 

This means that it is not captured by the block, but instead refers to a global / static variable that can be changed equally by the whole code.

+5
source

You must declare your block as a block variable:

 __block void (^_test_closure)(); _test_closure = ^{ NSLog(@"Running..."); if ((arc4random() % 100) > 50) { _test_closure(); } } _test_closure(); 
+8
source

It works with Xcode 5 - no warnings, hold cycles:

 typedef void(^blockT)(); blockT block1; blockT __block block1recursive; block1recursive = block1 = ^(){ block1recursive(); }; block1(); 
+2
source

All Articles