Blocks and Variables

来源:互联网 发布:dns测速软件 编辑:程序博客网 时间:2024/06/10 18:09

本章描述了blocks和变量的相互作用,包含内存管理。


Types of Variable

在block的代码体里,变量有五个不同的地方。你可以引用3个标准变量类型,就像你在function里引用一样。

全局变量,包括局部静态变量

全局functions(不是技术上的变量)

在block作用域里的局部变量和参数


Blocks 也支持其他两种变量类型:

   1.  在function层面上是__block变量,他们在block(和作用域里)是可变的,如果任意引用的block被copy到堆里,

       他们会被保存。

   2. const imports


最后,在一个方法的实现里,blocks可能会引用OC实例变量----看Object and Block Variables.


以下规则适用于block里使用的变量:

    1. 全局变量可访问,包括作用域里的静态变量

    2. 传入block的参数可访问(就像function的参数(形参))

    3. 局部于作用域里的栈(非静态)变量可以像const变量一样被获取到

        他们的值会在program的block表达式里被获取。在嵌套的blocks里,他们的值从最近的作用域里得到。

    4. 用__block存储修饰符声明的局部变量,并以引用的方式提供,这样他们就是可变的。

        对该变量的任意改变都会反映到整个作用域,包括任意其他的定义在该作用域内的blocks。这些会在The __block Storage Type. 更加详细地阐述。

    5. 在block里定义的局部变量,行为完全像function的局部变量。

       每次调用block都会提供一份新的变量copy,这些变量可以依次被当做const使用,或者在封闭在block里的

       blocks(嵌套block?)中当引用变量使用。


以下例子解析了局部非静态变量的使用

int x = 123;
 
void (^printXAndY)(int) = ^(int y) {
 
    printf("%d %d\n", x, y);
};
 
printXAndY(456); // prints: 123 456


如前所述,在block里试图被x赋一个新值将会产生一个error

int x = 123;
 
void (^printXAndY)(int) = ^(int y) {
 
    x = x + y; // error
    printf("%d %d\n", x, y);
};

为了允许一个变量能够在block里改变,你使用__block存储修饰符-----参考The __block Storage Type.


The __block Storage Type

你可以通过__block存储修饰符来声明一个输入变量为可变的,即可读写。对于局部变量,__block存储类似于但互斥于register,auto和static存储类型。

__block变量寄存在   变量的作用域、所有blocks  和  在变量作用域内声明或createed的  block的 copy   的共享内存里。所以,如果 声明在该域内的  任意blocks的  copy 声明周期比该域长时(例如,在某个地方enqueued以便后续执行), 这块内存在栈销毁时将会幸存下来。在一个指定范围内的多个blocks可以同时使用一个共享的变量。


作为优化,快存储开始于栈,就像blocks他们自己一样。如果block用Block_copy(或者在OC,当block被发送一个copy消息),变量会被copy到堆,所以,__block变量的地址可以随时间变化的。

对于__block变量有两个进一步的约束:他们不能为  可变长度的数组,不能为  包含C99可变长度数组的结构体。


下面例子解析了__block变量的使用:


__block int x = 123; //  x lives in block storage
 
void (^printXAndY)(int) = ^(int y) {
 
    x = x + y;
    printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456
// x is now 579


以下例子展示了blocks和不同类型 变量相互作用

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
 
{
    NSInteger localCounter = 42;
    __block char localCharacter;
 
    void (^aBlock)(void) = ^(void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter fixed at block creation
        localCharacter = 'a'; // sets localCharacter in enclosing scope
    };
 
    ++localCounter; // unseen by the block
    localCharacter = 'b';
 
    aBlock(); // execute the block
    // localCharacter now 'a'
}


Object and Block Variables

Blocks 支持OC、C++对象和其他的blocks最为变量

Objective-C Objects

当block被拷贝时,他为block里使用的对象变量创建一个强引用。如果你在一个方法的实现里使用block:

  • 如果你通过引用(by reference)访问一个实例变量,一个强引用会指向self
  • 如果你通过值(by value)访问一个实例变量,一个强引用会指向该变量


以下的例子解析这两种不同情况:


dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});
 
 
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});


为特定的对象变量覆盖这种行为,你可以使用__block存储修饰符来标识他。

C++ Objects

通常情况下你可以在block里使用C++对象,在一个成员函数里,引用成员变量和函数是通过暗指的this指针,所以会呈现出可变性。如果一个block被拷贝,有两个注意事项:

  • 如果你有一个__block存储的类,类里有一个基于stack的C++对象,通常使用拷贝构造函数
  • 如果你在一个block里使用其他基于stack的C++对象,他必须有一个const的拷贝构造函数,C++对象会使用这个构造函数来复制的。

Blocks

当你拷贝一个block时,如果有必要的话,任何在这个block里被引用的其他blocks都会被拷贝——整棵树都可能会被拷贝(自顶向下)。如果你有block变量和你引用一个  来自于该block内的 block,那么那个block(标红的block???)将会被拷贝。







0 0
原创粉丝点击