棘手的 Objective-C 块行为

A Tricky Objective-C Blocks Behavior

我很乐意得到对以下行为的解释:

typedef void (^MyBlock)(void);
MyBlock g_ary[4];

int runBlockParam2(MyBlock callbackBlock, int num) {
    g_ary[num] = callbackBlock;
    return num+100;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int i;
        for (i=0; i<4; i++) {
            __block int j;
            int k = runBlockParam2(^{
                NSLog(@"in the block i=%i, j=%i", i, j);
            }, i);
            j=k;
        }
        for (i=0; i<4; i++) {
            g_ary[i]();
        }
    }
    return 0;
}

以上代码显示以下输出: in the block i=0, j=100 in the block i=1, j=101 in the block i=2, j=102 in the block i=3, j=103

为什么j被块后面的赋值修改了?

有趣的是,如果我们删除 __block 修饰符,我们将得到: in the block i=0, j=0 in the block i=1, j=100 in the block i=2, j=101 in the block i=3, j=102

如果对上述行为有任何解释,我将不胜感激!

__block 存储类型会导致块外变量的任何更改在块内可见,反之亦然。在块本身之前的 j = k 行 运行s 在第二个 for 循环中是 运行,因此块在分配后会看到 j

删除 __block 会导致块捕获 j 的值,因为它是在赋值之前创建块时的值。您在删除 __block 后调用未定义的行为,因为您在 j 初始化之前捕获它,这会导致奇怪的输出。

如果您将声明更改为 int j = 0,那么日志语句将如您所料全部显示 j=0

with __block j 变量将作为指针传递到块中,因此如果您在赋值后调用块 j=k j 现在是 100。

没有 __block 只有 j 变量的值被传递到块中。在传递值的块定义之后,块本身无法更改 j。所以 j 是 0