码神之路:Object-C篇Object-C

八、Object-C 块对象

2018-08-30  本文已影响3人  Yink_Liu

Objective-C学习索引

块对象定义

语法:^ (参数列) { 主体 }
定义块对象,以下代码输出5,12。

void (^a)(int) = ^(int i){ printf("%d\n",i); }
a(5);
a(6 * 2);

块对象使用

typedef int (^block)(int);
block a = ^(int i) { return i+1; }

int (^blocksa[3])(int);
block blocksb[3];

void (^blocka)(void) = ^(void){ /*....*/ };
void (^blockb)(void) = ^{ /*....*/ };
void (^blockc) () = ^() { /*....*/ };

1、typedef int (^block)(int);定义一个返回值为int型的块对象,并用typedef简化声明
2、block a = ^(int i) { return i+1; }利用声明定义一个a的块对象,并实现快对象。
3、bloksa和blocksb类似,代表定义了含三个block的块对象的块数组。
4、blocka,blockb,blockc是三种定义方式,代表参数列为无参时可以省略,或只保留括号

块对象的捕获

我们先看一个很有意思的例子

int a = 1;//全局变量

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        static int b = 2;//静态变量
        int c = 3;//局部变量
        void (^block)(void) = ^ {
            printf("a = %d, b = %d, c = %d \n",a,b,c);
        };
        
        block();
        
        a = 4;
        b = 5;
        c = 6;
        block();
        
        block = ^ {
            printf("a = %d, b = %d, c = %d \n",a,b,c);
        };
        block();
    }
    return 0;
}

打印结果如下:

2018-08-29 15:06:59.492420+0800 test[15881:1509181] Hello, World!
a = 1, b = 2, c = 3 
a = 4, b = 5, c = 3 
a = 4, b = 5, c = 6 
Program ended with exit code: 0

由此输出我们可以对块主体访问变量总结如下:
1、全局变量和静态变量,可以访问和改变他们的值。
2、局部变量(栈内变量)只能访问,不能修改。因为它是先被保存起来,然后再访问,所以原本的变量哪怕变了,块主体内也不知道。如果在块内容中修改其值,会抱错。带入块的参数也属于局部变量。
3、额外一点,块内不能访问数组,否则会报错:Cannot refer to declaration with an array type inside block
由此,捕获的概念就出来了
捕获:块主体会把栈内变量等执行环境封装起来,块内读取块之外的变量。

__block变量

理解__block变量我们也用一个例子来说明

int a = 0;
void (^block)(void) = NULL;
void func(int n){
    __block int b = 0;
    void (^b1)(void) = ^{
        b += 1;
        printf("n = %d, a = %d, b = %d\n",n,++a,b);
    };
    void (^b2)(void) = ^{
        b += 100;
        printf("n = %d, a = %d, b = %d\n",n,++a,b);
    };
    b1();
    b2();
    block = [b1 copy];
    b = 10000;
    n = 99999;
    b2();
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        void (^b)(void) = NULL;
        func(1);
        b = block;
        b();
        func(2);
        b();
    }
    return 0;
}

输出如下:

2018-08-30 10:35:22.751335+0800 test[24294:2032994] Hello, World!
n = 1, a = 1, b = 1
n = 1, a = 2, b = 101
n = 1, a = 3, b = 10100
n = 1, a = 4, b = 10101
n = 2, a = 5, b = 1
n = 2, a = 6, b = 101
n = 2, a = 7, b = 10100
n = 1, a = 8, b = 10102
Program ended with exit code: 0

1、同一个__blick变量作用域内,块共享__block变量。
2、__block变量是在同一作用域的块对象执行时动态生成,若有有一个块对象还存在,__block变量就存在。由此,被复制的块对象也是能共享__block变量。
3、注意看最后一条输出,道理就是第二条说的,因为copy的block对象作用域还是和copy之前的b1作用域相同。所以__block变量还是之前的值。当然n是局部变量,也是同样道理。
4、ARC下只能用copy方法,原本还有一个叫Block_copy的方法,这里不能用因为已经定义(void *)形参指针。

上一篇 下一篇

猜你喜欢

热点阅读