我知道 Objective-C 块可以捕获和设置其封闭范围之外的变量值。它是如何做到的?
3 回答
It's actually fairly straightforward and described in Clang's Block Implementation Spec, in the "Imported Variables" section.
When the compiler encounters a Block like:
^{ if( numBalloons > numClowns) abort(); }
it creates a literal structure that includes -- among other things -- two elements that are important here. There's a function pointer to the executable code in the Block, and a const
field for each variable that's referred to inside the Block. Something like this:
struct __block_literal_1 {
/* other fields */
void (*invoke)(struct __block_literal_1 *);
/* ... */
const int numBalloons;
const int numClowns;
};
Notice that the invoke
function will take a pointer to a struct of the kind that's being defined right here; that is, the Block passes itself in when executing its code. Thus, the code gets access to the members of the structure.
Right after the declaration, the compiler creates a definition of the Block, which simply uses the referenced variables to initialize the correct fields in the struct
:
struct __block_literal_1 __block_literal_1 = {
/* Other fields */
__block_invoke_2, /* This function was also created by the compiler. */
/* ... */
numBalloons, /* These two are the exact same variables as */
numClowns /* those referred to in the Block literal that you wrote. *
};
Then, inside the invoke
function, references to the captured variables are made like any other member of a struct, the_block->numBalloons
.
The situation for object-type variables is a little more complicated, but the same principle applies.
在块对象的代码主体中,可以用五种不同的方式处理变量。
您可以引用三种标准类型的变量,就像引用函数一样:
- 全局变量,包括静态局部变量
- 全局函数(在技术上不是变量)
- 封闭范围内的局部变量和参数
块还支持另外两种类型的变量:
在功能级别是
__block
变量。这些在块(和封闭范围)内是可变的,并且如果任何引用块被复制到堆中,它们就会被保留。
const
进口。最后,在方法实现中,块可以引用 Objective-C 实例变量——参见对象和块变量。
以下规则适用于块内使用的变量:
全局变量是可访问的,包括存在于封闭词法范围内的静态变量。
传递给块的参数是可访问的(就像函数的参数一样)。
封闭词法范围的本地堆栈(非静态)变量被捕获为
const
变量。它们的值取自程序中块表达式的位置。在嵌套块中,值是从最近的封闭范围捕获的。
使用存储修饰符声明的封闭词法范围的局部变量
__block
由引用提供,因此是可变的。任何更改都反映在封闭词法范围中,包括在同一封闭词法范围内定义的任何其他块。这些在 __block 存储类型中有更详细的讨论。
在块的词法范围内声明的局部变量,其行为与函数中的局部变量完全相同。
块的每次调用都会提供该变量的新副本。这些变量又可以用作
const
包含在块中的块中的变量或引用变量。
从这里:http:
//developer.apple.com/library/ios/#documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html
基本上,块“对象”包含块对象内部的一个变量(如块对象的“实例变量”),用于每个捕获的局部变量。(Josh Caswell 的回答提供了有关如何实现的更多详细信息。)创建块时,将当时捕获的每个局部变量的值复制到块内的相应变量中。每当在块内使用变量时,它都会在块内使用此变量。