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语言数组变量)
}
参考资料
- <<Objective-C 高级编程: iOS与OSX多线程和内存管理>>
网友评论