15

我知道 Objective-C 块可以捕获和设置其封闭范围之外的变量值。它是如何做到的?

4

3 回答 3

26

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.

于 2013-07-23T19:17:07.843 回答
6

在块对象的代码主体中,可以用五种不同的方式处理变量。

您可以引用三种标准类型的变量,就像引用函数一样:

  • 全局变量,包括静态局部变量
  • 全局函数(在技术上不是变量)
  • 封闭范围内的局部变量和参数

块还支持另外两种类型的变量:

  1. 在功能级别是__block变量。这些在块(和封闭范围)内是可变的,并且如果任何引用块被复制到堆中,它们就会被保留。

  2. const进口。

最后,在方法实现中,块可以引用 Objective-C 实例变量——参见对象和块变量。

以下规则适用于块内使用的变量:

  1. 全局变量是可访问的,包括存在于封闭词法范围内的静态变量。

  2. 传递给块的参数是可访问的(就像函数的参数一样)。

  3. 封闭词法范围的本地堆栈(非静态)变量被捕获为const变量。

    它们的值取自程序中块表达式的位置。在嵌套块中,值是从最近的封闭范围捕获的。

  4. 使用存储修饰符声明的封闭词法范围的局部变量__block由引用提供,因此是可变的。

    任何更改都反映在封闭词法范围中,包括在同一封闭词法范围内定义的任何其他块。这些在 __block 存储类型中有更详细的讨论。

  5. 在块的词法范围内声明的局部变量,其行为与函数中的局部变量完全相同。

块的每次调用都会提供该变量的新副本。这些变量又可以用作const包含在块中的块中的变量或引用变量。

从这里:http:
//developer.apple.com/library/ios/#documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html

于 2013-07-23T15:06:18.590 回答
0

基本上,块“对象”包含块对象内部的一个变量(如块对象的“实例变量”),用于每个捕获的局部变量。(Josh Caswell 的回答提供了有关如何实现的更多详细信息。)创建块时,将当时捕获的每个局部变量的值复制到块内的相应变量中。每当在块内使用变量时,它都会在块内使用此变量。

于 2013-07-24T01:06:00.953 回答