什么是block
Blocks是C语言的扩充功能,可以用一句话来表示Blocks的扩充功能:带有自动变量(局部变量)
的匿名函数
。
所谓匿名函数
就是不带有名称的函数
。C语言的标准不允许存在这样的函数。例如以下源码:
int func (int count);
它声明了名称为func
的函数。下面的源码中为了调用函数,必须使用该函数的名称func
。
int result = func(10);
如果像下面这样,使用函数指针
来代替直接调用函数,那么似乎不用知道函数名也能够使用该函数。
int result = (*funcptr)(10);
但其实使用函数指针也仍需要知道函数名称。
int (*funcptr)(int) = &func;
int result = (*funcptr)(10);
而通过Blocks,源代码中就能够使用匿名函数
,即不带函数名称的函数。对于程序员来说,命名占用了很大比重,函数名,变量名,方法名,属性名,类名和框架名
等都必须具备,而能够编写不带名称的函数对于程序员来说相当具有吸引力。
现在我们知道了匿名函数
的概念。那么带有自动变量值
又是什么呢?我们先来回顾一下在C语言函数中可能使用的变量
。
自动变量(局部变量)
函数的参数
静态变量(静态局部变量)
静态全局变量
全局变量
其中在函数的多次调用之间能够传递值的变量有,静态变量(静态局部变量)
,静态全局变量
,全局变量
。
虽然这些变量的作用域不同
,但在整个程序当中,一个变量总保持在一个内存区域
。因此虽然多次调用函数,但该变量值总保持不变,在任何时候以任何状态调用,使用的都是同样的变量值。
C++和Objective-C
使用类可保持变量值且能够多次持有该变量自身
。它会声明持有成员变量
的类,由类生成的实例
或对象
保持该成员变量
的值。但是声明并实现C++,Objective-C
的类增加了代码的长度。这时我们就要用到Blocks了。Blocks提供了类似由C++和Objective-C类
生成实例或对象
来保持变量值的方法。
Block语法
完整形式的Block语法与一般的C语言函数定义相比,仅有两点不同。没有函数名,带有“^”。Block语法的BN范式如下:
^
返回值类型
参数列表
表达式
例如以下形式:
^int (int count) {return count + 1}
Block的语法可以省略很多东西,我们可以省略其返回值
,如果不使用参数
,我们也可以省略其参数列表
,返回值类型
以及参数列表
均被省略的Block语法应该是最常见的记述方式。
Block类型变量
在Block语法下,可将Block语法
赋值给声明为Block类型
的变量中,即源代码中一旦使用Block语法
就相当于生成了可赋值给Block类型
变量的“值”。Block中由Block语法生成的值
也被称为“Block”。“Block”既指源代码中的Block语法
,也指由Block语法所生成的值
。
int (^blk)(int) = ^int (int count) {return count + 1}
在日常开发中我们会经常使用typedef
来声明Block类型的变量
typedef void (^myTestBlock)(NSString *参数1,NSString *参数2);
调用
self.myTestBlock(参数1, 参数2);
取得回调
self.myTestBlock = ^(NSString *参数1, NSString *参数2) {
};
截获自动变量值
我们之前已经了解到了带有自动变量(局部变量)
的匿名函数
中的匿名函数
,那么带有自动变量值
究竟是什么呢?其实它在Block中表现为“截获自动变量值”。实例如下:
- (void)testBlock{
int dmy = 256;
int val = 10;
void (^blk)(void) = ^{
NSLog(@"%d,%d",dmy,val);
};
val = 2;
blk();
}
Blocks中,Block表达式截获
所使用的自动变量的值
,即保持该自动变量
的瞬间值
,所以在执行Block语法后,即使改写
Block中使用的自动变量
的值也不会影响
Block执行时自动变量
的值。
2018-10-19 15:26:20.873463+0800 testDemo[74354:1089050] 256,10
执行结果并不是改写后的值,在Block执行时这些值被保存,从而在执行块时使用,这就是自动变量值的截获。
_ _block说明符
实际上,自动变量值截获只能保存执行Block语法瞬间的值。保存后就不能改写该值,我们尝试改写截获的自动变量值,看看会出现什么结果。
int main(){
int val = 0;
void (^block)(void) = ^{
val = 1;
};
block();
printf("block");
return 0;
}
该段代码会产生编译错误。
Variable is not assignable (missing __block type specifier)
若想在Block语法的表达式中
将值赋给在Block语法外声明
的自动变量,需要在该自动变量上附加__block
说明符。
int main(){
__block int val = 0;
void (^block)(void) = ^{
val = 1;
};
block();
printf("val = %d\n",val);
return 0;
}
执行结果:
val = 1
总结
这一篇先讲解了一些block的概念,规范,功能以及一些用法,下一篇将着重记录Block的实现,在深究其原理前先明白block的相关特性将对后续的学习有很大的帮助。