棘手的Objective-C阻止行为

时间:2016-08-02 15:10:19

标签: ios objective-c objective-c-blocks

我很高兴得到以下行为的解释:

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

我会对上述行为的任何解释表示感谢!

2 个答案:

答案 0 :(得分:3)

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

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

如果您将声明更改为int j = 0,则日志语句将显示j=0,如您所料。

答案 1 :(得分:0)

使用__block将j变量作为指针传递给块,因此如果在赋值j=k之后调用块,则j现在为100。

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