Block的那些事
程序员文章站
2022-07-12 23:15:38
...
Block是什么
1、block是一种数据类型,所以我们可以声明一个block类型的变量
2、block类型的变量专门用来存储一段代码,这段代码可以有参数,可以有返回值
Block的故事
UIButton就像是一件衣服,一般人会直接不加修饰的穿上,可以实现它作为一件衣服的功能,但是不能突显它真正的漂亮。优秀的人根据自己的理解,进行部门的修改并且还搭配一些小饰品,穿出来的就不仅仅是一件衣服,更像是艺术品。UIButton可以简单用也可以复杂用,关键看你怎么用。
Block的声明方法:
- block的声明: 必须指定block变量的返回值和参数类型
- block的声明规范: 返回类型(^block变量名称)(参数列表)
void (^block1)(); //无返回值无参数 名为block1的声明
void (^block2)(int num1); //无返回值一个参数名为block2的声明
int (^block3)(int num1, int num2); //有返回值两个参数名为block3的声明
Block的初始化方法:
- block的初始化 :写一段符合block要求的代码段进行存储
- 初始化规范:^返回类型(参数列表){代码块}
- 初始化的过程中注意block的实现要和block的声明对应,返回值和参数列表一一对应。
block1 = ^void () {
NSLog(@"我是无参数无返回值的代码段");
};
block2 = ^void(int num2){
num2 = num2 + 1;
NSLog(@"num2 = %d",num2);
};
block3 = ^int(int num1, int num2){
int num = num1 + num2;
NSLog(@"num = %d",num);
return num;
};
Block的执行:
- 如同函数调用
block1(); //无返回值无参数的调用
block2(5); //无返回值有参数的调用
int res = block3(3,4); //又返回值有参数的调用
Block实现过程的简写:
- 代码段没有返回值,那么代码段的void可以省略
- 代码段没有参数,那么代码段的()可以省略
- 注意:block实现的时候可以省略,声明的过程不符合以上规则
block1 = ^{
NSLog(@"我是无参数无返回值的代码段");
};
block2 = ^(int num2){
num2 = num2 + 1;
NSLog(@"num2 = %d",num2);
};
- 无论代码段是否有返回值,在实现block的时候,可以不写返回类型,返回类型可以全部省略。(经常使用)
block1 = ^() {
NSLog(@"我是无参数无返回值的代码段");
};
block2 = ^(int num2){
num2 = num2 + 1;
NSLog(@"num2 = %d",num2);
};
block3 = ^(int num1, int num2){ //省略返回类型 int
int num = num1 + num2;
NSLog(@"num = %d",num);
return num;
};
- 如果不写返回类型,系统会自动确定返回类型,通过判断block内部是否有return语句,如有多个return语句,必须返回的都是同一个类型的数据。如果没有return语句就默认void
int(^block4)(int,int) = ^(int num1, int num2){
if(num1 > num2){
return 1;
}
else{
return 2.0; //这里会报错 改为2即可
}
};
使用typedef简写Block声明:
typedef void(^TypeBlock)();
TypeBlock block4 = block1;
block4();
typedef void(^TypeBlock2)(int);
TypeBlock2 block5 = block2;
block5(5);
typedef int(^TypeBlock3)(int,int);
TypeBlock3 block6 = block3;
block6(3,4);
block内部访问外部变量:
- 1、在block代码块内部可以访问定义在外部的变量的值,定义在外部的局部变量和全局变量
- 2、在block代码块的内部可以修改全局变量的值,但是不能修改定义在外部的局部变量的值
- 3、如果要修改block代码块外部定义的局部变量的值,那就为这个局部变量加上__block
int number1 = 100;
__block int number3 = 300;
TypeBlock block7 = ^(){
int number2 = 200;
//number1++; 加上此句会报错,因为不能修改block块外部局部变量的值
number2++;
number3++;
NSLog(@"num = %d ",number1);
NSLog(@"num = %d ",number2);
NSLog(@"num = %d ",number3);
};
block7();
block作为函数参数:
- 可以将调用者自己写的代码传递到函数的内部执行
typedef void(^TypeBlock)();
void test(TypeBlock block) //定义block为参数的两个函数
{
NSLog(@"------");
block();
NSLog(@"------");
}
typedef int(^TypeBlock3)(int,int);
int test2(TypeBlock3 block)
{
NSLog(@"+++++++");
int res = block(3,4);
NSLog(@"+++++++");
return res;
}
test(block1); //block1是上面声明实现过的 block1是先初始化完成后再调用的
test(^{
NSLog(@"我是参数block"); //参数内容直接自己写,两种方式均可; 第二种偏多。
});
test2(block3); //block3也是上面实现过的
test2(^int(int num1, int num2) {
int res = num1 + num2;
NSLog(@"res = %d",res);
return res;
});
- block 作为函数参数,让调用者参与函数方法内部的实现,下面我们来体会一下
我们创建一个类,里面有一个数组,添加一个初始化的方法和一个遍历的方法
@interface Array : NSObject
{
int _arr[10];
}
- (instancetype)init;
- (void)Traverse : (void(^)(int val)) block;
@end
类的实现:
@interface Array : NSObject
{
int _arr[10];
}
- (instancetype)init;
- (void)Traverse : (void(^)(int val)) block;
@end
#import "Array.h"
@implementation Array
- (instancetype)init
{
if (self = [super init])
{
for (int i = 1; i < 11; i++)
{
_arr[i-1] = i * 10; //给数组内元素赋值
}
}
return self;
}
- (void)Traverse : (void(^)(int val)) block
{
for (int i = 0; i < 10; i++)
{
block(_arr[i]); //让调用者自己通过block来控制对数组元素的操作
}
}
@end
调用者:
记得先#import "Array.h"
然后在主函数中:
Array *arr = [Array new];
[arr Traverse:^(int val) {
if (val > 50) //调用者自己写对数组元素的操作。可以任意修改以满足需求。
NSLog(@"%d",val);
}];
- 是不是感觉这个函数活了,调用者可以自己去控制函数内部的实现过程,每次主要改动block就可以实现新的操作
- 之前我们之前直接调用,然后遍历数组并输出,有任何改动要需要重写函数
block作为函数返回值
- block作为函数返回值必须使用typedef的方式,否则无法编译通过
//错误方法:
void(^)() test4()
{
TypeBlock block1;
return block1;
}
//正确方法:
typedef void(^TypeBlock)();
TypeBlock test3()
{
return ^{
NSLog(@"block作为函数返回参数可以使用");
};
}
Block的基础学习至此先告一段落,这些目前可以简单使用了,老铁你会了吗。