iOS Block学习笔记(二) -- Block截获与修改自动变量

Block捕获自动变量的值

Block匿名函数又称为带自动变量值的匿名函数, 前面我们已经知道了匿名函数, 而带自动变量值如何理解?

我们知道函数中可以可能使用的变量如下:

1. 自动变量(局部变量)
2. 函数的参数
3. 静态局部变量
4. 静态全局变量
5. 全局变量

而在函数的多次执行过程中, 能够传递的变量有:

1. 静态局部变量
2. 静态全局变量
3. 全局变量

通常情况下,我们在OC/C++中可以保持变量值且使用类对象来保持变量,并且能够多次持有该变量.

然而,Blocks提供了这种类似于类的保存变量值的方式,并且能够多次持有该变量. 因此使用Block可以不用声明类也无需使用全局变量/静态变量,就能够满足这种条件.

如下代码可以证明:

int main() {
    int dmy = 256;
    int val = 10;
    const char *fmt = "val = %d\n";
    void (^blk)(void) = ^ {printf(fmt, val);};

    val = 2;
    fmt = "These values were changed. val = %d\n";

    blk();

    return 0;
}

最后结果运行结果答应: val = 10.

表示Block中可以截获所使用的自动变量的值, 即保存自动变量在创建Block的瞬时值. 因为Block保存的是瞬时值, 在执行Block语法以后,即使修改了自动变量的值,也不会影响Block中捕获的自动变量在Block运行时候的值.

__block变量修饰符

前面,我们了解到Block能在执行创建Block语法时,自动变量的瞬时值. 但是一旦截获该瞬时值, 在Block代码中是无法修改的, 编译器会报错.

int val = 0;
void (^blk)(void) = ^{ val = 1;}; // 编译时,这里就会报错.

但是如果被截获的自动变量是OC类对象,也是无法修改该对象的值, 但是能够操作该对象的成员变量.

id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{ 
    [array appendObject:@(1)];// 不会报错,可以正常运行
    array = [[NSMutableArray alloc] init]; // 会报错, 无法修改自动变量的值
};

OC提供__block修饰符,用于修饰自动变量,此时我们就能在Block语法中修改被截获的自动变量值.

__block int val = 0;
void (^blk)(void) = ^{ val = 1;};// 因为val是__block修饰,因此可以修改
blk();
printf("val = %d\n", val);

该源码执行的结果是: val = 1. 对于对象类型的变量,也能使用__block进行修饰

__block id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{ 
    [array appendObject:@(1)];// 不会报错,可以正常运行
    array = [[NSMutableArray alloc] init]; // 不会报错, 可以修改__block自动变量的值
};
blk();

注意Block并没有实现对C预言数组的截获:

const char text[] = "hello";
void (^blk)(void) = ^ {
    printf("%c\n", text[2]); //这里会出错, 因为Block并没有实现对C预言数组的截获
}

我们一般使用指针来规避该问题:

const char *text = "hello";
void (^blk)(void) = ^ {
    printf("%c\n", text[2]); //Block可以截获指针变量(但是无法截获C语言数组变量)
}

参考资料

  1. <<Objective-C 高级编程: iOS与OSX多线程和内存管理>>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容