blocks
blocks是c语言的扩充,他是:带有自动变量(局部变量)的匿名函数。
这个概念叫做:闭包。如python中的lambda,在c++11中也引入了lambda;
*中关于闭包:闭包(Closure)是词法闭包(Lexical
Closure)的简称,是引用了*变量的函数。这个被引用的*变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
blocks的语法:
^ 返回值类型 参数列表 表达式
^ 参数列表 表达式
^ 表达式
^void (int i){ printf("%d", i);}
^(int i){printf("%d", i);}
^{printf("123");}
这里要注意,当你省略返回值类型的时候,你的表达式里return返回什么类型,那么你的返回值类型就是什么。
当你不适用参数的时候,(void) 参数列表可以省略。
在使用block的时候,我们可以声明block变量,他同c中的函数指针:
int f(int a) { return a; } int (*fa)(int) = &f;
在blocks中,block指源代码中的block语法,也指由block语法生成的值。
int (^blk)(int); int (^blk)(int) = ^(int a){ printf("%d, a); } int (^blk1)(int) = blk; int (^blk2)(int); blk2 = blk1;
void f(int (^blk)(int)); //向函数传递block
int (^f()(int)); //将block作为返回值返回。
可以使用typedef:
typedef int (^blk_t)(int); void f(int (^blk)(int)) 对应: void f(blk_t blk) int (^f()(int)) 对应: blk_t f();
比较函数指针:
int (*ff(int))(int *, int);
这个有点难理解了,我们要从里往外看:
ff(int) 这里将ff声明为一个函数,它有一个int的形参。
这个函数的返回值就是int (*)(int *, int);
这是一个指向函数的指针。我们来变一下形式:
[cpp] view
plaincopy
- typedef int (*func)(int*, int);
- func ff(int)
这里可以看到,他们只有一个* 和一个 ^ 的区别。
他可以作为:自动变量,函数参数,静态变量,静态全局变量,全局变量使用。
block类型变量可以和c语言中其他类型变量一样使用。
如:
typedef int (^blk_t)(int); blk_t blk = ^(int count){return count;}; blk_t *blkptr = &blk; (*blkptr)(10);
自动变量
来说一下自动变量:
block表达式截获所使用的自动变量的值:保存该自动变量的瞬间值。
代码解释:
int val = 0; void (^blk)(void) = ^{printf("%d", val);}; val = 3; blk();
此时,输出的是0而不是3.
__block
自动变量值截获只能保存执行block语法瞬间的值,保存后不能改写了。 当你在block改写截获的自动变量时,会产生编译错误。
如果想要在block语法的表达式中将值付给block语法外声明的自动变量,那么需要在这个自动变量上附加__weak说明符:
__block int a = 0;
void (^blk)(void) = ^{a = 1;};
blk();
获取的自动变量
id array = [[NSMutableArray alloc]init]; void (^blk)(void) = ^{id obj = [[NSObject alloc]init]; [array addObject:obj];}; id array = [[NSMutableArray alloc]init]; void (^blk)(void) = ^{array = [[NSMutableArray alloc]init];};
上面两段代码第二段会出现错误,应该加上__block说明符。 因为向截获的变量array赋值会产生编译错误。但是使用截获的值是不会产生任何问题的。
const char text[] = "hello";
void (^blk)(void) = ^{printf("%c", text[2]);};
const char *text = "hello";
void (^blk)(void) = ^{printf("%c", text[2]);};
上面两段代码会出现不同的结果,第一段会报错,因为截获自动变量的方法没有实现对c数组的截获。
-----2014/3/18 Beijing