Block
什么是block
能够截获自动变量的匿名函数,匿名函数也就是不带函数名的函数
block语法
^ 返回值类型 (参数列表){ 表达式 }
^int (int test){
return test;
};
- 当返回值类型为空时我们可以将返回值类型那一项省略或者写成void
^ (参数列表) { 表达式 }
^ void (参数列表) { 表达式 }
//返回值为空
^ (int test){
printf("%d",test);
};
^void (int test){
printf("%d",test);
};
- 当参数列表为空是我们也可以将其省略或写成void
^ void { 表达式 }
^ void (void) { 表达式 }
^{
printf("hello world!");
};
^void (void){
printf("hello world!");
};
block类型变量的声明
返回值类型 (^变量名) (参数列表);
//声明一个返回值为 int 类型,有一个 int 类型参数的block
int (^block) (int);
//给上面声明的block类型变量赋值
block = ^int (int test){
printf("%d",test);
return test + 1;
};
用typedef定义block
在使用block时,对于相同返回值相同参数的 block 变量我们可能会多次使用到,如果每次使用的时候都声明一次会比较麻烦,这个时候我们就可以使用 typedef 来定义 block。
//定义一个返回值,参数列表都为空的block类型,名为voidBlock
typedef void(^voidBlock)(void);
//声明一个 voidBlock 类型的变量
voidBlock block = ^(){
NSLog(@"voidblock");
};
block();
截获自动变量
int a = 1;
void (^block) (void) = ^{
NSLog(@"block a = %d",a);
};
a += 1;
block();
NSLog(@"%d",a);
上述代码的打印结果为
2018-10-13 12:29:46.903008+0800 block[966:985286] block a = 1
2018-10-13 12:29:46.903157+0800 block[966:985286] 2
block能够截获其代码块中所使用的自动变量的值,它会保存该自动变量的瞬间值。由于它保存的是自动变量的瞬间值,所以在执行 block 语法后再去改变该变量的值并不会对 block 中所使用的变量值产生影响。
__block 说明符
- block 只能截取保存自动变量的瞬间值,而不能修改该变量
int a = 1;
void (^block) (void) = ^{
a = a + 1;
};
block();
以上代码在 block 中改变了变量 a 的值,我们会发现这样的代码会发生编译错误
Variable is not assignable (missing __block type specifier)
- 如果要在block中修改自动变量的值,我们需要用 __block 修饰该变量
__block int a = 1; void (^block) (void) = ^{ a = a + 1; NSLog(@"block a = %d",a); }; block(); //这段代码的执行结果为block a = 2
- 上面我们提到block会保存自动变量的瞬间值,从而在执行 block 语法后再去改变该变量的值并不会对 block 中所使用的变量值产生影响,但是如果使用 __block 修饰该自动变量,则该变量的值可以发生改变。
-
__block int a = 1; void (^block) (void) = ^{ NSLog(@"block a = %d",a); }; a += 1; block(); NSLog(@"%d",a);
上述代码的执行结果为,block 中 a 的值是改变后的值
2018-10-13 17:05:11.004404+0800 block[2677:3608745] block a = 2 2018-10-13 17:05:11.004553+0800 block[2677:3608745] 2
- block 与 OC 对象,在 block 中不能直接给 OC 对象赋值,但是可以调用改变的该对象的方法。例如:
NSMutableArray *array = [NSMutableArray array]; void (^block) (void) = ^{ [array addObject:@"block"]; NSLog(@"%lu",(unsigned long)array.count); }; block();
上述代码的执行结果
2018-10-13 17:12:37.390769+0800 block[2748:3689145] 1
这是因为在block中,截获的自动变量 array 是对象指针,该指针指向 NSMutableArray 对象,执行 [array addObject:@"block"] 并没有直接改变该指针变量的值,所以该操作是合法的。但是不可以直接给 array 赋值,否则会发生编译错误。例如以下代码就会发生编译错误:
NSMutableArray *array = [NSMutableArray array]; void (^block) (void) = ^{ array = nil; }; block();