block代码块
- 代码块对象简称为”代码块”,是对 C语言中函数的扩展.运行在 iOS4.0和 OS X 10.6版本以上
- 代码块实际上是由 C语言实现的,所以在各种以 C 作为基础的语言内都是有效地,其中包括: Objective-C,C++以及 Objective-C++.
- 代码块不属于 ANSI 的 C语言标准,但是关于代码块的提议已经提交给了美国标准委员会审议.
- 代码块本质上是和其他变量相似.不同的是,代码块储存的数据是一个函数体.使用代码块时,可以像调用其他标准函数一样,传入参数,并且得到返回值.
- 因为其定义、调用用法与函数指针基本相似,所以先复习下函数指针的用法
函数指针的语法格式
void (*pMyFunction)(void);
其中,按照左右法则,先看括号中的未标示的字符, pMyFunction, 其前面有一个*,说明其实一个指针,再往右看是一个括号,则说明其是一个函数指针,名字是 pMyFunction, 后面的参数为空,前面的返回值亦为空.
接下来在 X-Code 中写一个例子来帮助大家理解
#import <Founction/Foundation.h>
//声明了一个数据类型 void (*) (void) 给其去一个别名:pMyFunctionRef
typedef void (*pMyFunctionRef) (void);
//实例化一个对象
pMyFunctionRef pMyFunction;
//声明两个函数
void myFunction(void);
void anotherFunction(void);
int main(int argc,const char * argv[]){
@autoreleasepool {
pMyFunction = myFunction;
//通过函数指针来调用函数
pMyFunction();
pMyFunction = anotherFunction;
pMyFunction();
//在创建一个函数指针变量,这个指针变量要存放的函数也是返回类型为空,形参是空
pMyFunctionRef pAnotherFunction;
pAnotherFunction = myFunction;
pAnotherFunction();
// 在这里,有人会说,你吃饱了撑得,直接调用 anotherFunction 就行了嘛其实不然看下面的两种方法,明显的不同第一种直接调用 anotherFunction 函数,再看第二种,把 anotherFunction 当做参数调用,相当于函数调用函数,这样就强大了
anotherFunction();
callBack(anotherFunction);
}
return 0;
}
//下面的__ fun___ 是 C 中内置的宏,这里的作用的代表这个函数的名字
void myFunction(void){
NSLog(@"%s",__func__);
}
void anotherFunction(void){
NSLog(@"%s",__func__);
}
void callBack(pMyFuntionRef fun)
{
fun();
}
代码块的语法格式
与函数指针类似,主要区别就是*换成了^,而且 block块中还有代码片段,掉用方式基本同函数指针相似.
<returntype> (^blockname)(list of arguments) = ^(arguments){body;};
举一个简单的例子
#import <Founction/Foundation.h>
//定义 myBlock函数,形参是 block 块,返回值为空
//定义的 block 块名 block,形参为空,返回值为空
void myBlcok(void (^blcok)());
int main(int argc,const char * argv[]){
@autoreleasepool {
void (^theBlcok)();
theBlcok = ^{NSLog(@"I am a block");};
//上面的两句可以用一句表示 void (^theBlock)() = ^{NSLog(@"I am a block");};
//调用块
myBlock(theBlock);
}
return 0;
}
void myBlcok(void (^blcok)())
{
blcok();
}
结果是打印出 I am a block
与函数指针对比一下, 其调用方法都几乎是一样的,改变的是*号变成了^,也就是脱字号,其返回值还可以省略,只不过代码块中的是一段代码而已,可以是一个函数.
再来一个例子,输入几个人的名字,实现名字的排序功能,其主代码如下
NSArray *students = @[@"ZhangSan",@"LiSi",@"WangWu",@"ZhaoLiu",@"MaQi"];
NSLog(@"unsorted array info:%@",students);
//这里使用的NSComparisonResult就是一个 block 块,他是一个枚举类型
NSArray *sortedStudents = [students
sortedArrayUsingComparator:^NSComparisonResult (id obj1, id obj2) {
return [obj1 compare:obj2];}
];
NSLog(@"sorted students info:%@",sortedStudents);
其结果是:unsorted array info:(
ZhangSan,
LiSi,
WangWu,
ZhaoLiu,
MaQi
)
2015-06-27 22:03:52.107 BlocksDemo[2990:1834086] sorted students info:(
LiSi,
MaQi,
WangWu,
ZhangSan,
ZhaoLiu
)
代码块的变量
关于代码块局部变量
typedef int (^blockType)(void);
//关于局部变量
int myInt = 100;
int anotherInt = 200;
// 在block内部可以访问和其同一作用域的变量
blockType blk = ^{return myInt * anotherInt;};
int result = blk();
NSLog(@"the result is %d",result);
myInt = 10;
anotherInt = 20;
// 在这里根据打印结果来看,其最后的值还是20000,所以说对于block来说, 对于局部变量在其定义的时候实际已经赋值。后续是不能修改的
result = blk();
NSLog(@"after modify myInt=10,anotherInt = 20 ther result is %d",result);
关于代码块的全局变量
//声明了一个 block 块的类型,类型的名称是: blockType
typedef int (^blockType)(void);
//关于全局变量
static int myInt = 100;
static int anotherInt = 200;
blockType blk = ^{return myInt * anotherInt;};
NSLog(@"the result is %d",blk());
myInt = 10;
anotherInt = 30;
NSLog(@"after modify myInt = 10, and anotherInt = 30 the result is %d",blk());
代码一开头就是用了 typedef, 声明了一个block块的类型,类型的名称是:blockType **
以后如果想声明一个block对象用于返回类型是整型,有一个整型参数的block块的时候, 可以使用blockType类型来声明
关于修改代码块外部变量
如果想修改代码块外部的局部变量, 需要在声明这个变量的时候, 用__block来修饰
//关于修改代码块外部变量
// int result = 100;
__block int result = 100;
int (^quare_block)(int number) = ^(int number){result = number * number; return result;};
NSLog(@"after modify the int result with __block int result:%d",quare_block(20));
用__ block 修饰的代码块的局部变量是可以修改的,对于 block 来说, result 是一个外部变量,原先的值是100,用__block 修饰后,在块的代码中修改 result 的值为20 ,输出的结果: after modify the int result with __block int result:400