深入理解代替单纯记忆
block语法
block变量声明格式:返回值类型(^ 变量名)(参数列表)
int (^block1)(int ,int);
void (^block2)(void);
block定义格式:^返回值类型(参数列表){操作主体}
//以下两种写法等同(当可以推断出函数体返回值类型时,可以省略返回值类型)
^int(int a, int b){
NSLog(@"block1");
return 1;
};
^(int a,int b){
NSLog(@"in block1");
return 1;
};
//然而下面的写法则是错误的
//xcode提示错误信息: Incompatible block pointer types assigning to 'long (^__strong)(int, int)' from 'int (^)(int, int)'
/*
long (^longMethod)(int a, int b);
longMethod = ^ (int a, int b){
return a + b;
};
*/
------------------分割线-----------------------
//以下两种写法效果等同(当函数体不需要参数时,()可以省略)
^(){
NSLog(@"in block2");
};
^{
NSLog(@"in block2");
};
block声明+定义
int (^block3)(int,int) = ^(int a,int b){
NSLog(@"in block3");
return a+b;
};
void (^block4)() = ^{
NSLog(@"in block4");
};
- 使用typedef定义一个block类型 PS:既然block可以当做一种数据类型,同时block变量的声明又略显麻烦,那么也可以使用typedef来将block的声明换一个别名。
typedef int (^block_typedef1)(int,int);
typedef void(^block_typedef2)();
//下面的typedef声明写法是根据typedef对于普通数据类型正确的写法,但是对于block是错误的。
/*
typedef int (^)(int,int) block_typedef3;
*/
//下面typedef写法错误,函数体无参数也不能省略()
/*
typedef void(^block_typedef3);
*/
//使用typedef定义的block
block_typedef1 block5 = ^ int (int a,int b){
NSLog(@"in block5");
return a+b;
};
block使用
PS:从实参、形参、调用三个角度来看block的使用
//block作为实参
//block变量作为实参
[self OC_function1:@"block变量作为实参" andBlock:block3];
[self OC_function2:@"block变量作为实参" andBlock:block4];
[self OC_function1:@"block变量作为实参" andBlock:block5];
//block实现作为实参
[self OC_function1:@"block实现(即定义)作为实参" andBlock:^(int a, int b){
return a+b;
}];
//block作为形参
-(void)OC_function1:(NSString *)string1 andBlock:(int (^)(int,int))block{
//block调用
int c = block(1,1);
NSLog(@"%@,block执行结果:%d",string1,c);
}
-(void)OC_function2:(NSString *)string1 andBlock:(void (^)())block{
//block调用
block();
//下面的语句也可以正常执行
/*
block(1,2,3,4);
*/
NSLog(@"%@",string1);
}
//typdef在block形参中的应用
-(void)OC_function4:(NSString *)string1 andBlock:(block_typedef1) block{
}
//下面的写法是错误的
//本来感觉形参的写法应该类似普通函数,即按照block变量声明格式来写即可,但事实并非如此
/*
-(void)OC_function3:(NSString *)string1 andBlock:(int (^block)(int,int)){
}
*/
总结
基本的语法和使用已经介绍完。但从上面代码注释来看,有些地方的写法是可以省略一些符号的,另外,书写格式上有些容易出错的地方,现一并总结。
- 关于省略 例如省略表示参数列表的"()"、表示返回值类型的"void"等。
- block变量声明中、typdef中不能省略任何符号,省略只能出现在**block的实现(定义)**中。
- 在block实现中,三种请况下可以省略:
-
函数体不需要参数时,"()"可以省略。
-
函数体没有返回值时,"void"可以省略。
-
系统能够推断出函数体的返回值类型时,返回值类型可以省略。
-
关于书写格式
- 形参的书写 最后一个方法OC_function3中,我自认为block形参的写法可以和普通数据类型那样,把变量声明的格式搬过来就可以,但实则不然。
- typedef为block类型起别名时 需要像声明block变量一样为block类型起别名,这与普通数据类型使用typedef不同。
后记(持续更新)
尽管知道了block的写法,我对block还是有些害怕和好奇,不知道这个写法奇葩的东西是怎样被创造出来的,碰到了什么样的问题,才提出这个东西。我也查了一些相关资料,发现还是有些问题需要继续探索,现在记录下来,等到了那个合适的时候,我会继续深究。
- 闭包(或者相关概念如匿名函数)的发展历史?脚本语言等一些语言中都有相关的特性,闭包的好处是什么?和block的产生又有什么联系?
- block的声明和C中的函数指针还是很类似的,他们之间有什么联系?
- block的底层实现用了C的结构体,如果有必要,需要深究一下block的完整实现。--关于block底层的实现,可以参考《Objective-c高级编程》
- block在OC中可以当做对象来对待,block的内存管理有什么怎样的?--同样参考《Objective-c高级编程》
相关资料
-
cnblogs上一篇关于block的讲解(PS:重点是这个博客上有iOS几乎所有知识的讲解,中文、全面、理解到位,好教程)。