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的名字使用定义的这个block了,例:
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定义的时候,将外部变量截取,在block中这个变量值不再改变。如例所示,在定义block的时候已经将变量截取了。所以在block中,m=0。不会因为外部m改变而改变。所以输出的是0,不是3。
实际他的具体实现是因为创建block的时候有一个赋值操作,将外部变量进行了复制。
{
int m=0;
int (^block)(void) = ^ int {
int inblock = m;
NSLog(@"in block m=%d",inblock);
return 1;
};
m = 3;
block();
}
block的具体实现类似上面这段代码,block会自带一个变量inblock。在block创建的时候会用这个变量保存外部变量m,block内部使用到m的地方,都会用inblock代替。所以当外部的m改变时,和block内部m的使用已经完全没关系了。
普通情况下是不能在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的变量将不会拥有截取自动变量的功能。原理上来说,加上__block之后,block内部的inblock将不会赋值,而是直接使用外部变量。不会具有截取自动变量功能。我们来用例子看看。
{
__block int m=0;
int (^block)(void) = ^ int {
NSLog(@"in block m=%d",m);
return 1;
};
m = 3;
block();
}
输出:in block m=3
使用上面截取自动变量的例子。在变量定义时候加上
__block。输出完全变了。block将不再拥有截取自动变量的功能
4.Block使用copy
每个block都会有自己的作用域,在超出作用域的时候,有时不使用copy的话,会导致崩溃,特别是非ARC的情况下,下面我们来看看什么时候不需要copy,什么时候需要copy
①在未使用外部变量的情况下,block属于全局变量,不需要copy
bbk = ^{
NSLog(@"abcde");
};
②.其他情况下,除了使用GCD之外,都最好使用copy,否则就会有崩溃的风险