需要解释for循环中的块行为

时间:2014-01-26 12:29:55

标签: objective-c for-loop objective-c-blocks

请看一下这段代码:

NSMutableArray *array = [NSMutableArray array];

for (int i = 0; i < 10; i++)
{
    void (^b)() = ^{printf("%d\n", i);};
    [array addObject:b];
}

for (id obj in array)
{
    void(^b)() = obj;
    b();
}

[array removeAllObjects];

我希望这段代码能输出0,1,2等等,但总是打印9。但为什么?它不会在每次循环迭代中捕获我吗?为什么总是捕获最后一个值?但对我来说更令人困惑的是,如果我改变这一行:

 void (^b)() = ^{printf("%d\n", i);};

void (^b)() = [^{printf("%d\n", i);} copy];

然后它开始打印0,1,2等等。任何人都可以解释为什么它会这样运作吗?

1 个答案:

答案 0 :(得分:4)

这不是块捕获的问题,而是存储在array中的块。如果在第一次循环后打印块的地址,则应该看到相同的地址被打印:

for (id obj in array)
{
    printf("%p\n", (void*)obj);
}

这是因为所有十个块都是在一个循环中在堆栈上创建的,并且放在同一个地址上。循环结束后,在其中创建的块超出范围。引用它是未定义的行为。但是,既然你存储了块的地址,你就可以引用它(非法)。

由于在循环中创建的最后一个块已捕获i的最后一个值(即9),因此从第二个循环中对块进行的所有调用都会调用打印九个块的同一个块。

如果复制块,则此行为会更改,因为现在在创建它的范围之外引用它是完全合法的。现在你的所有块都有不同的地址,因此每个块都会打印出不同的数字。