1.block的语法:
block定义的标准方法为:
^返回值类型 (参数列表) {表达式}
例如:
- ^ int (void) {
- return 1;
- };
其中int是返回值类型。void是参数列表,表示不传参数。{}中的是表达式。
但是当一些情况下,有的参数是可以省略的。下面就说一下这些省略的情况
①. 当返回值类型是void的时候,void可以省略
例如:
- ^ void (void) {
- NSLog(@"这是block");
- };
- ^ (void) {
- NSLog(@"这是block");
- };
②.当参数是void的时候,参数也是可以省略的。例如:
- ^ (void) {
- NSLog(@"这是block");
- };
- ^{
- NSLog(@"这是block");
- };
2. block的申明
有的时候当block定义之前需要申明。下面我们来看看block申明的方法:
返回值类型 (^block的名字) (参数列表)
例如:
- int (^block)(int) = ^ int (int a){
- return a+1;
- };
等号前面的就是block的申明。申明的block必须和赋值的block一致,否则会出现编译错误
3. block的使用
①block当成变量使用
block其实也是一种变量,可以把他当成一个变量使用,最常用的方法是在文件头先定义一个block。用申明的方法定义。例如:
- typedef int (^block) (int);
- block selfBlock = ^ int (int a){
- return a+1;
- };
- int (^block)(int) = ^ int (int a){
- return a+1;
- };
前面一个是直接像使用变量一样使用block,类似int a =... 这里就用 block a =...。
②block截取自动变量和改变外部变量值
block具有截取自动变量的功能。例:
- {
- int m=0;
- int (^block)(void) = ^ int {
- NSLog(@"in block m=%d",m);
- return 1;
- };
- m = 3;
- block();
- }
- 输出:in block m=0
实际他的具体实现是因为创建block的时候有一个赋值操作,将外部变量进行了复制。
- {
- int m=0;
- int (^block)(void) = ^ int {
- int inblock = m;
- NSLog(@"in block m=%d",inblock);
- return 1;
- };
- m = 3;
- block();
- }
普通情况下是不能在block中改变外部变量的值的,如上面所说,因为block内部的外部变量都是赋值来的,所以是无法改变的,如果直接在内部写上改变值的代码,在编译的时候,会报编译错误。如图所示。
如果真的想改变变量的值,可以在定义变量的时候使用__block。
- {
- __block int m=0;
- int (^block)(void) = ^ int {
- m = 1;
- NSLog(@"in block m=%d",m);
- return 1;
- };
- m = 3;
- block();
- }
- {
- __block int m=0;
- int (^block)(void) = ^ int {
- NSLog(@"in block m=%d",m);
- return 1;
- };
- m = 3;
- block();
- }
- 输出:in block m=3
4.Block使用copy
每个block都会有自己的作用域,在超出作用域的时候,有时不使用copy的话,会导致崩溃,特别是非ARC的情况下,下面我们来看看什么时候不需要copy,什么时候需要copy
①在未使用外部变量的情况下,block属于全局变量,不需要copy
- bbk = ^{
- NSLog(@"abcde");
- };
②.其他情况下,除了使用GCD之外,都最好使用copy,否则就会有崩溃的风险