OC语言中的block|青训营笔记

126 阅读4分钟

这是我参与「第四届青训营」笔记创作活动的的第十一天。block是OC语言在c语言的基础上新增的数据类型之一,本篇文章旨在简单介绍一下OC语言中的block。

一、闭包

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。闭包本身是一个结构体,存储了函数入口地址和与之绑定的一系列环境,环境里面既有其本身内部定义的变量,又包含从外部捕获的变量,捕获变量的处理因实现而异。

二、block基本介绍

Objective-C中闭包的实现就是block。

Block是一个数据类型,所以可以声明这个数据类型的变量,也可以声明一个block类型的变量。block在声明时有三个组成部分:返回值,block的名称,和block传入的参数;而在给block赋值时,没有block名称这一部分,在对应的位置用返回值代替。

block变量的声明的语法:

returnType (^blockName)(parameters);

也就是 返回值类型 (^block变量的名称)(参数列表);

举例:

void (^blockName)();

这表示我声明了一个叫做blockName的block类型的变量,在这个变量中只能存储没有返回值和没有参数的代码。

int (^blockName)();

这表示我声明了一个叫做blockName的block类型的变量,在这个变量中只能存储返回值为int并且没有参数的代码。

int (^blockName)(int num);

这表示我声明了一个叫做blockName的block类型的变量,在这个变量中只能存储返回值为int并且有一个整值参数的代码。

注意:在声明block变量的时候必须要指定此变量存储的代码是否有参数和返回值,指定后就只能存储指定的代码。

初始化block变量/赋值

写一个符合block要求的代码段存储到block变量中。

书写格式

^returnType(parameters) { 
// do something; 
};

也就是 ^返回值类型 (参数列表){代码;};

举例:

int (^sumBlock)(int a, int b) = ^int(int a, int b) {
  return a + b;
};

这说明^int(int a, int b) {return a + b;};被赋值给了一个存储返回值为int并且有两个整值参数的代码。所以sumBlock现在存储了^int(int a, int b) {return a + b;};这个代码。

注意:赋值给block变量的代码段必须要符合block变量指定的代码。

执行存储在block变量中的代码

block变量名();

举例:

对于只有返回值没有参数的代码:

   int (^myBlock)() = ^int(){
        int num = 10+20;
        return num;
    };
    
    int sum = myBlock();
    NSLog(@"sum = %d", sum);
    

用一个变量接收执行存储在block变量中的代码就可以了。

对于有返回值有参数的代码:

int (^myBlock2)(int mun1, int num2) = ^int(int num1, int num2){
        int num3 = num1+num2;
        return num3;
    };
    
    int sum2 = myBlock2(10,20);
    NSLog(@"sum2 = %d", sum);

block的简写

如果代码段没有返回值,那就可以省略void,声明block的返回值不可以省略。如果代码段没有参数,那么代码段的()可以省略。

在代码段无参数的情况下可以就只写^{ }。

 int (^myBlock)() = ^{
        int num = 10+20;
        return num;
    };

注意:block变量的声明不可以省略()。

声明block变量的时候如果有指定参数的话可以只写参数类型,省略参数名称。

举例:

int (^myBlock2)(int, int) = ^(int num1, int num2){
        int num3 = num1+num2;
        return num3;
    };

注意:代码段的参数名称不能省略。

typedef

为了简化block声明,我们会给常用block声明定义别名,只需要在block声明的左边加上关键字typedeftypedef可以将一个长类型定义为一个短类型。也可以使用它将长的block类型定义为一个短类型。

注意:由于我们这里相当于声明了一种类型,所以block变量名在typedef时的命名一般与类的命名相同,首字母大写。

typedef returnType (^blockName)(parameters);

举例:

typedef void (^blockName)();

这说明重新定义了一个叫做blockName的无参数无返回值的类型。

思考

block类型的变量中可以存储什么样的数据?

此类型的变量中专门存储一段可以有参数和返回值的代码。但是不是所有的代码都可以存进去,在声明block变量的时候必须要指定此变量存储的代码是否有参数和返回值。指定后就只能存储指定的代码。

如果在代码段中省略了返回值,系统会如何判断返回值?

如果代码段中没有返回任何数据,那么系统会认为这个代码段是没有返回值的;如果代码段中有返回数据,返回的数据是什么类型,系统就会认为这个代码段是什么类型。

Reference

《闭包与 Objective-C block》juejin.cn/post/712344…

《Closure》www.google.com/search?q=cl…