Block是什么
Block是带有自动变量的匿名函数。如字面意思,Block没有函数名,另外Block带有插入记号"^",插入记号便于查找到Block,后面跟的一个括号表示块所需要的一个参数列表。和函数一样,可以给块传递参数,并且也具有返回值。不同点在于,块定义在函数或者方法内部,并且能够访问在函数或方法范围内的任何变量。通常情况下,这些变量能够访问但不能改变其值,有一个特殊的块修改器(由块前面由两个下划线字符组成)能够修改块内变量的值。
Block的语法
Block的完整语法格式如下:
^ returnType (argument list) {expressions}
与 C 语言函数的区别:
- 没有函数名
- 带有 “^” 符号
我们写一个完整的Block:
^ int (int x) { return x; }
也可以写省略格式的Block,比如省略返回值:
^ (int x) { return x; }
Block省略返回值类型时,如果表达式中有return语句就使用该返回值的类型,没有return语句就使用void类型。
如果没有参数也可以省略参数列表:
^ { NSLog(@"Hello World"); }
像上面这么些,其实也生成了可赋值给Block类型的值,我们可以这么接收:
int (^myBlock)(int) = ^ int (int index) { return index; }
int (^block1)(int) = myBlock;
如果每次写 block 变量的时候都这样写,那不是很麻烦吗。我们可以使用 typedef 来定义一个 block 类型:
typedef int(^MyBlock)(int);
然后就可以使用 MyBlock 这个类型来定义变量了:
MyBlock blk_t = ^ (int index) { return index; }
Block类型变量可以作为自动变量,函数参数,静态变量,全局变量使用。比如将块定义在main函数外部,就可以将它扩展到全局范围。
Block截取变量
- 截获自动变量:如果在 block 中使用到上文中的局部变量的话,block 会将其保存到自身的内部中,不管下文那个变量怎么变,在 block 调用的时候,用的变量值都是之前截获的那个值。比如下面代码,程序的输出结果为:10
int var = 10;
MyBlock block = ^ { NSLog(@"%d", var); };
var = 20;
block();
注意:如果在Block中修改val的值会报错!
不过不用担心,我们可以用__block修饰符来实现在变量block中修改值的需求。
__block int var = 10;
MyBlock block = ^ {
var = 20;
NSLog(@"%d", var);
};
block();
这样程序输出结果就为20
- 对于全局变量、静态全局变量、静态变量在块中可以修改。
- 如果修改的是Objective-C对象,例如NSArray对象,不可以对其赋值但是可以增删元素。并且同样可以通过__block修饰符进行变量修改。
- 不能在block中访问C语言字符数组
const char text[] = "text";
MyBlock block = ^ {
NSLog(@"%c", text[2]);
};
这样会造成编译报错,因为block中并没有实现对C语言字符数组的截获,可以将其改成指针形式:
const char *text = "text";
MyBlock block = ^ {
NSLog(@"%c", text[2]);
};