1、简介
Block也叫代码块或块,保存了一段代码,方便在程序中调用,简化OC编程
2、块
2.1 格式
^块的返回值类型(参数类型 参数名, 参数类型 参数名) {
}块执行体
2.2 说明
1.^是块的标志,块必须以^开头
2.块的返回值类型可以省略
3.块无需指定块的名字
4.如果块没有参数,后面的括号也要保留,括号内部可以为空,建议使用void
2.3 举例
^int(int a,int b) {
};return a+b;
3、块变量
3.1 格式
块的返回值类型^(块的变量名)(参数类型,参数类型);
3.2 强调
定义块变量无需声明参数的名字,声明参数的类型即可,没有参数建议使用void
3.3 举例
int (^myBlock)();
4、块变量赋值
// 无参 + 无返回值 void (^myBlock)() = ^void(){ NSLog(@"Block..."); }; // 有参 + 有返回值 int (^addBlock)(int,int) = ^int(int a,int b){ return a+b; }; // 有参 + 无返回值 void (^printBlock)(NSString *) = ^(NSString *info){ NSLog(@"info =%@", info); };
4、块与局部变量
4.1 不可修改局部变量的值
4.1.1 关键代码
int x = 1; NSLog(@"1 ··· x = %d", x); // 1 { x = 3; NSLog(@"2 ··· x = %d", x); // 3 } void (^printBlock)() = ^(){ // 强调:Block不允许直接修改局部变量的值 // x = 20; NSLog(@"B ··· x = %d", x); }; x = 5; NSLog(@"3 ··· x = %d", x); // 5 printBlock(); // 3,调用块之后,局部变量的值没有改变 NSLog(@"4 ··· x = %d", x); // 5
4.1.2 打印结果
1 ··· x = 1 2 ··· x = 3 3 ··· x = 5 B ··· x = 3 4 ··· x = 5
4.1.3 结果分析
结论:块允许访问局部变量,但是不允许修改局部变量的值,而且块是调用的时候才执行,与定义的位置无关,本质上传递的是值
原因:系统在定义块的时候就把局部变量的值保存在了块中,而不是在执行块的时候再去访问
4.2 可以修改局部变量的值
4.2.1 关键代码
__block int x = 2; NSLog(@"x = %d", x); // x = 2 void (^print)(void) = ^(void){ NSLog(@"a ... %d", x); x = 5; NSLog(@"b ... %d", x); }; x = 4; NSLog(@"c ... %d", x); // c ... 4; print(); // a ... 4, b ... 5 NSLog(@"d ... %d", x); // d ... 5
4.2.2 打印结果
x = 2 c ... 4 a ... 4 b ... 5 d ... 5
4.2.3 结果分析
结论:使用__block修饰的局部变量是允许被块修改的,仍然是调用的时候才访问并修改值
原因:系统在定义块的时候,并没有保存__block修饰的局部变量,因此可以修改该局部变量的值
说明:static修饰局部变量也可以达到这个效果,因为__block和static修饰局部变量的值的时候,本质上传递的都是该变量的地址,而不是值
5、块与全局变量
关键代码
int num = 10; int main(int argc, const char * argv[]) { void (^block)() = ^{ NSLog(@"num=%d", num); }; num = 20; block(); return 0; }
打印结果
num=20
结果分析
block可以一直引用全局变量的值,因为它传递的是全局变量的地址
6、自定义块类型
typedefvoid (^BlockType)(NSString *); typedefint (^addBlockType)(int, int); BlockType print = ^(NSString *message){ NSLog(@"%@", message); }; addBlockType sherry = ^int(int a, int b) { return a+b; }; print(@"conan..."); // conan... NSLog(@"x = %d", sherry(2, 3)); // x = 5