7

伙计们,

我正在尝试做一个调用自身的函数,但将所有内容放在一个块上,

如您所见,以下函数旨在被无限次调用(直到 arcrandom 返回小于 50 的数字),并且您应该期望输出可变数量的“RUNNING”消息,具体取决于机会。

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

_test_closure();

但是,在运行它时,我得到一个 EXC_BAD_ACCESS 错误,我发现的原因是当代码尝试在闭包内调用 _test_closure 时,它​​基本上没有指向任何地方。

有谁知道如何使上述代码工作?

4

3 回答 3

8

您必须将块本身声明为块变量:

__block void (^_test_closure)();


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

_test_closure();
于 2012-08-26T21:12:33.803 回答
5

递归和块是棘手的。因为一个块捕获了所有传入的变量,所以变量_test_closure还没有初始化(并且clang应该给你一个警告:

块指针变量“_test_closure”在被块捕获时未初始化

)。

有几种方法可以解决这个问题,但最明显和最简单的是将块本身设为__block变量(@H2CO3 所说的)。这样就可以让块weak-linked差不多了,这样当你再次调用它的时候,它就被正确地初始化了。

您可以选择的另一个选项是将块设为全局或静态,如下所示:

// 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);
    }
} 

这意味着它不会被块捕获,而是引用全局/静态变量,所有代码都可以平等地更改该变量。

于 2012-08-26T21:16:27.720 回答
2

它适用于 XCode 5 - 没有警告,没有保留周期:

typedef void(^blockT)();

blockT block1;
blockT __block block1recursive;

block1recursive = block1 = ^(){
    block1recursive();
};

block1();
于 2014-03-13T11:25:27.473 回答