Objective-C block语法备忘

2,783 阅读4分钟

深入理解代替单纯记忆

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"等。
  1. block变量声明中、typdef中不能省略任何符号,省略只能出现在**block的实现(定义)**中。
  2. 在block实现中,三种请况下可以省略:
  • 函数体不需要参数时,"()"可以省略。

  • 函数体没有返回值时,"void"可以省略。

  • 系统能够推断出函数体的返回值类型时,返回值类型可以省略。

  • 关于书写格式

    1. 形参的书写 最后一个方法OC_function3中,我自认为block形参的写法可以和普通数据类型那样,把变量声明的格式搬过来就可以,但实则不然。
    2. typedef为block类型起别名时 需要像声明block变量一样为block类型起别名,这与普通数据类型使用typedef不同。

后记(持续更新)

尽管知道了block的写法,我对block还是有些害怕和好奇,不知道这个写法奇葩的东西是怎样被创造出来的,碰到了什么样的问题,才提出这个东西。我也查了一些相关资料,发现还是有些问题需要继续探索,现在记录下来,等到了那个合适的时候,我会继续深究。

  • 闭包(或者相关概念如匿名函数)的发展历史?脚本语言等一些语言中都有相关的特性,闭包的好处是什么?和block的产生又有什么联系?
  • block的声明和C中的函数指针还是很类似的,他们之间有什么联系?
  • block的底层实现用了C的结构体,如果有必要,需要深究一下block的完整实现。--关于block底层的实现,可以参考《Objective-c高级编程》
  • block在OC中可以当做对象来对待,block的内存管理有什么怎样的?--同样参考《Objective-c高级编程》

相关资料