Pab*_*blo 9 objective-c objective-c-blocks
我知道在堆栈中创建了块.但是,由于我对堆栈和局部变量知之甚少,我无法理解为什么我应该将块移动到堆中以获得预期的结果.直观地,我觉得块代码块在堆栈中只有1个实例,这段代码引用了i3次局部变量.如果我将它复制到堆,它将有3个不同的实例,每次它将i在复制过程中捕获3个不同的值.但我真的想更多地了解堆栈中的块代码,堆和引用局部变量.
for (int i=0; i<3; i++)
b[i] = ^{ return i;};
for (int i=0; i<3; i++)
printf("b %d\n", b[i]());
Run Code Online (Sandbox Code Playgroud)
bbu*_*bum 13
范围,伙计.作用域.
重写为:
void georgeClinton() {
int (^b[3])(); // iirc
// georgeClinton's scope
for (int i=0; i<3; i++) {
// for's scope
b[i] = ^{ return i;};
}
}
Run Code Online (Sandbox Code Playgroud)
在每次传递for()循环时,for的范围实际上是一个新的范围.但是,当然,范围在堆栈中.
当你调用georgeClinton()时,你有效地将 georgeClinton()的范围推送到堆栈上.当georgeClinton()以一些时髦的善良返回时,georgeClinton()的范围会从堆栈中弹出,使堆栈处于推送发生时的状态(可能会对返回值进行修改).
一个for()循环是一回事; 每次迭代都会将状态推送到堆栈并在迭代结束时将其弹出.
因此,如果您在for()循环的迭代中将任何内容存储在堆栈中,就像块一样,那么该东西将在迭代结束时被销毁.要保留它,必须将其移动到堆(您可以控制任何给定分配状态的生命周期).
关键是块类型变量实际上是一个指针; 它是对定义块的结构的引用.他们从堆栈开始提高效率,这可能导致像这样的微妙问题.
注意一个块实际上是两件事; 它是对实现块的不可变代码的引用(实际上就像一个函数指针),它是对块中捕获的数据的描述,以及在复制时如何将数据移动到堆中.
也就是说,块是数据和代码的组合.永远不会改变的代码.作为执行指针捕获的数据通过定义块的表达式(即块"关闭"当前执行状态).
是后一点绊倒了你; 当在堆栈上创建块时,它会创建带有插槽以保存捕获的数据,也可以在堆栈上创建.