1

试图了解blocks在objective-c中是如何工作的。阅读苹果文档时遇到下一个问题(链接

这是一个我们不应该使用块的例子:

void dontDoThis() {
    void (^blockArray[3])(void);  // an array of 3 block references

    for (int i = 0; i < 3; ++i) {
        blockArray[i] = ^{ printf("hello, %d\n", i); };
        // WRONG: The block literal scope is the "for" loop.
    }
}

但是我们怎样才能得到 3 个不同的块来打印“hello, 0”、“hello, 1”和“hello, 2”呢?我尝试了许多不同的方法,但每次我得到“你好,2”三遍。

4

2 回答 2

8

块在堆栈上开始生命,因此,块的生命周期仅与声明它的范围一样长。

for() 循环的主体——{} 中的循环主体——本身就是一个范围。因此,您的代码将对堆栈 [块] 上的某些内容的引用放入周围范围 [语言数组] 中的变量中。

您需要将块复制到堆以使其生存:

void dontDoThis() {
    void (^blockArray[3])(void);  // an array of 3 block references

    for (int i = 0; i < 3; ++i) {
        blockArray[i] = [^{ printf("hello, %d\n", i); } copy];
    }
}

如果不使用 ARC,您还需要-release在某些时候复制块。

您可能会发现这篇博客文章很方便(我是在 Blocks 公开后不久写的)。这篇文章介绍了一些技巧、窍门和陷阱


等等——是的——你是对的。ARC 编译器中发生了一些神奇的事情,导致块似乎神奇地在堆上。但是,我在 LLVM 文档中找不到任何明确记录此行为的内容。如果关闭 ARC,您会看到输出类似于 2,2,2 而不是 0,1,2。

这是一些新的行为。我不会依赖这种行为,直到有人可以在编译器中找到明确定义如何支持它的明确注释。


@autoreleasepool {
    void (^blockArray[3])(void);  // an array of 3 block references

    for (int i = 0; i < 3; ++i) {
        void (^block)(void) = ^{ printf("hello, %d\n", i); };
        NSLog(@"%p", block);
        blockArray[i] = block;
        NSLog(@"%p", blockArray[i]);
    }

    for (int i = 0; i < 3; ++i) blockArray[i]();
}

输出:

2012-12-24 16:15:36.752 jkdfjkfdjkdfjk[70708:303] 0x7fff5fbff838
2012-12-24 16:15:36.755 jkdfjkfdjkdfjk[70708:303] 0x100108160
2012-12-24 16:15:36.758 jkdfjkfdjkdfjk[70708:303] 0x7fff5fbff838
2012-12-24 16:15:36.759 jkdfjkfdjkdfjk[70708:303] 0x100108000
2012-12-24 16:15:36.760 jkdfjkfdjkdfjk[70708:303] 0x7fff5fbff838
2012-12-24 16:15:36.760 jkdfjkfdjkdfjk[70708:303] 0x100102e70
hello, 0
hello, 1
hello, 2

因此,块是在堆栈上创建的,并在 for() 循环范围之外的赋值时自动复制到堆中。

一个类似的测试还表明,当作为参数传递给 NSArray 的 addObject: 时,该块将被复制。

于 2012-12-24T22:37:15.830 回答
4

如果你真的想让它工作,你可以使用 anNSMutableArray而不是 C 数组。 NSMutableArray *blocks = [NSMutableArray 数组];

for (int i = 0; i <= 3; i++) {
  blocks[i] = ^{ printf("hello %d\n", i); };
}

通过将它们添加到 an 中,NSMutableArray它们将从堆栈中复制到堆中,从而使它们能够超过for循环的范围。

正如@bbum 指出的那样,上述方法不起作用,我认为just work用 ARC 阻塞的想法太过分了。

您需要主动复制块才能使它们工作......所以以下应该工作

NSMutableArray *blocks = [NSMutableArray array];

for (int i = 0; i <= 3; i++) {
  blocks[i] = [^{ printf("hello %d\n", i); } copy];
}
于 2012-12-24T22:28:23.053 回答