Objective-C Blocks, Recursion Fails

岁酱吖の 提交于 2019-12-30 00:40:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!