为什么在复制块之前将__block变量移动到堆中?

时间:2013-02-26 05:49:47

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

我知道如果复制了访问它的Block,__block变量将从堆栈移到堆中。但是下面的测试代码告诉我,{<1}}变量在块复制之前被移动到堆

也就是说,四个输出是:stack =&gt; heap =&gt; heap =&gt;堆,这不是我期望的结果:stack =&gt; stack =&gt; stack =&gt;堆。

有人能把我拉直吗?

__block

3 个答案:

答案 0 :(得分:3)

让我先说一下:块很奇怪。

现在,当你开始时,你已经声明了一个变量x,并且还用__block作为前缀。无论如何,__block到底是什么?好吧,对于在块的词法范围内捕获的对象,变量是-retain',以便保证它们在执行块时出现。但是对于原始变量,块通过强制它们通过const值而不是通过引用来保护它们的值。通过预先__block,您可以让编译器自由执行命令,以便在复制块时将您的变量“神奇地”从堆栈移动到堆中。为了清楚起见,__block变量实际上是堆栈分配的,但是在复制块时它们会被移动到堆(malloc()'d)。

但是x的位置有什么奇怪的变化呢?好吧,再回到__block。因为你没有像正常变量那样使用const对x的引用,所以块使用(稍微讨厌)技巧:块创建指向任何__block变量的指针,如果该变量发生变异,它被解除引用。塔达!你的变量没有从堆栈移动到堆,块只是取消引用它的指针并将其移动到内存中!

所以,实际上,您对变量移动的位置和时间感到困惑。您的示例是记录正确的值。

答案 1 :(得分:2)

您的预期输出是基于您在步骤3-4之前不会复制块的假设。但是,块规范中的任何内容都不能保证这种情况。

是的,当您在其上明确地呼叫-copy时,将立即复制该块。但为什么不能早点复制呢?先前复制块永远不会错误。因此,当确切地复制一个块是未定义的时,你不应该依赖它。

ARC下的一些最新版本的编译器可能是保守的,并在创建后立即复制一个块。没有什么不妥。同样,如果它这样做,它将是一个实现细节,其他编译器或未来版本可能会做一些不同的事情。

答案 2 :(得分:0)

我在In Objective-C with ARC, what does compiler do when I define a block?

问了同样的问题

您在ARC中运行代码的情况

在ARC,

  

可保留对象所有者类型的块变量被移出   堆栈通过初始化堆副本与从中移动的结果   堆栈副本。

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#blocks

中的