问题
Sup guys,
I'm trying to do a function that calls itself but by putting everything on one block,
As you can see, the following function is intended to be called an indefinite amount of times (until arcrandom returns a number lower than 50) and you should expect as an output a variable number of "RUNNING" messages, depending on chance.
void (^_test_closure)(void) = ^ {
NSLog(@"RUNNING");
if(arc4random() % 100 > 50) {
_test_closure();
}
};
_test_closure();
However, when running it, I get an EXC_BAD_ACCESS error and the reason I've found is that when the code tries to calls _test_closure inside of the closure it basically points to nowhere.
Does anyone know how to make the above code work?
回答1:
Recursion and blocks is tricky. Because a block captures all variables passed in, the variable _test_closure
is not initialized yet (and clang should give you a warning:
Block pointer variable '_test_closure' is uninitialized when captured by block
).
There are several ways you can get around this, but the most obvious & simplest is to just make the block itself a __block
variable (what @H2CO3 said). This allows the block to be weak-linked
almost, so that when you call it again, it is properly initialized.
Another option you have is making the block a global or static, like this:
// 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 it's not being captured by the block, but instead it's referencing the global / static variable, which can be changed by all code equally.
回答2:
You have to declare your block itself as a block variable:
__block void (^_test_closure)();
_test_closure = ^{
NSLog(@"Running...");
if ((arc4random() % 100) > 50) {
_test_closure();
}
}
_test_closure();
回答3:
It works with XCode 5 - no warnings, no retain cycles:
typedef void(^blockT)();
blockT block1;
blockT __block block1recursive;
block1recursive = block1 = ^(){
block1recursive();
};
block1();
来源:https://stackoverflow.com/questions/12133907/objective-c-blocks-recursion-fails