一篇文章说明Block

什么是Blocks

Blocks是C语言的扩充功能。可以概括为:带有自动变量(局部变量)的匿名函数。
所谓的匿名函数,就是没有名字的函数,在C语言中是不允许的。
在计算机科学中,这种概念也称为:“闭包Closure”、“lambda计算”等。
而且一般而言,函数或者方法里是不能又出现一个函数的,但是Blocks作为一种数据类型,是可以的。通常Blocks用于封装代码。因为即便是写在函数体内部,不去调用它,就不会执行。

Blocks的声明

//无参数 无返回值
    void (^block1)(void) = ^void(void){
     
        NSLog(@"无参数 无返回值");
    };
    //无参数 无返回值 可省略表达
    void (^block2)(void) = ^{
     
        NSLog(@"无参数 无返回值");
    };
    
    //有参数 无返回值
    void (^block3)(NSString* name) = ^(NSString* name){
     
        NSLog(@"有参数 无返回值");
    };
    //有参数 无返回值 前面声明的参数名称可参略
    void (^block4)(NSString*) = ^(NSString* name){
     
        NSLog(@"有参数 无返回值");
    };
    
    //有参数 有返回值
    int (^block5)(NSString* name) = ^ int (NSString* name) {
     
        NSLog(@"有参数 有返回值");
        return 1;
    };
    
    int number = block5(@"haha");
    NSLog(@"howMuch : %d",number);

运行结果:

text2021[50774:5632858] 有参数 有返回值
text2021[50774:5632858] howMuch : 1

Blocks作为函数的参数

当Blocks作为参数时的书写格式比较怪异,要适应一下:
普通函数与Blocks函数对比:

- (void)block2:(NSString*)name{
     
    NSLog(@"name: %@",name);
}

- (void)block3:(void(^)())callBackBlock{
     
    NSLog(@"调用了block3");
    callBackBlock();
}

我们可以注意到在Block3的方法里面,调用了callBackBlock()方法。
我们看看如何调用:

- (void)block4{
     
    NSLog(@"执行block4");
    [self block3:^{
     
        NSLog(@"我又回到block4");
    }];
}

- (void)block3:(void(^)())callBackBlock{
     
    NSLog(@"调用了block3");
    callBackBlock();
}

运行结果:

text2021[51007:5682882] 执行block4
text2021[51007:5682882] 调用了block3
text2021[51007:5682882] 我又回到block4

由此可见,Blocks的作用就是改变原本代码的执行,如上述的结果,首先调用的是block4的方法,然后返回到block3处理了一下,再回到原来的地方接着处理block4.
它使得代码更加灵活。

带参数的Block回调

当有参数有返回值的blocks作为函数的参数的时候,写法更是复杂难记,但在开发中是十分常见的,因此只要熟悉、适应了就好。

- (void)block6{
     
    NSLog(@"执行block6");
    int spend = 5000;   //花费5000元
    //计算人均需要AA多少钱
    [self calculateInfo:^(int count, CGFloat discount) {
     
        NSLog(@"我又回到block6");
        CGFloat aa = spend / count * discount;
        NSLog(@"人均花费:%.2f",aa);
    }];
}

- (void)calculateInfo:(void (^)(int count,CGFloat discount))callBackBlock{
     
    NSLog(@"执行calculateInfo");
    int count = 50;     //人数为50人
    CGFloat discount = 0.8; //折扣为8折
    callBackBlock(count,discount);
}

运行结果:

text2021[52299:5985655] 执行block6
text2021[52299:5985655] 执行calculateInfo
text2021[52299:5985655] 我又回到block6
text2021[52299:5985655] 人均花费:80.00

Blocks的作用:封装

假设:有一个人类,每天的事情大部分都是千篇一律的,无非就是睡觉、吃饭、工作、学习、谈恋爱等等,虽然大部分相同,但也总是有些差异的。
如果将该人类的每一天要做的事情写成代码,大致上就是:

第一天:起床 吃饭 工作 吃饭 睡觉
第二天:起床 吃饭 谈恋爱 吃饭 睡觉
第三天:起床 吃饭 学习 吃饭 睡觉

那么我们可以发现三天里只有中间部分环节是不同的,显然如果这样编写代码,是效率非常低的,而Blocks就能解决这样的问题。
代码:

- (void)block7{
     
    [self date:@"day1" Daily:^{
     
        NSLog(@"工作");
    }];
    [self date:@"day2" Daily:^{
     
        NSLog(@"谈恋爱");
    }];
    [self date:@"day3" Daily:^{
     
        NSLog(@"学习");
    }];
}

- (void)date:(NSString*)date Daily:(void (^)(void))somethingDifferent{
     
    NSLog(@"%@",date);
    NSLog(@"起床");
    NSLog(@"吃饭");
    somethingDifferent();
    NSLog(@"吃饭");
    NSLog(@"睡觉");
}

运行结果:

text2021[55174:6433382] day1
text2021[55174:6433382] 起床
text2021[55174:6433382] 吃饭
text2021[55174:6433382] 工作
text2021[55174:6433382] 吃饭
text2021[55174:6433382] 睡觉
text2021[55174:6433382] day2
text2021[55174:6433382] 起床
text2021[55174:6433382] 吃饭
text2021[55174:6433382] 谈恋爱
text2021[55174:6433382] 吃饭
text2021[55174:6433382] 睡觉
text2021[55174:6433382] day3
text2021[55174:6433382] 起床
text2021[55174:6433382] 吃饭
text2021[55174:6433382] 学习
text2021[55174:6433382] 吃饭
text2021[55174:6433382] 睡觉

Blocks中的变量传递

在Blocks中我们可以使用局部变量,是因为从Blocks外部传递进来的局部变量,Block会视为是一个常量(不可改变的量),只读不可写。
如果要在Blocks内修改该局部变量,需要为该变量做一个__block 的声明,这样的话,编译器才会吧该变量的地址传进去block中。

- (void)block8{
     
    int number = 10;
    
    void (^test)(void) = ^{
     //只是声明Block,不会被调用
        NSLog(@"%d",number);//可读
        number = 20;
    };
    
    test(); //调用Blocks
}

应改为:

	__block int number = 10;
    
    void (^test)(void) = ^{
     
        NSLog(@"%d",number);//可读
        number = 20;
    };
    
    test();

另注意:在block内部使用对象的时候,会对对象有一个强引用,知悉即可。

你可能感兴趣的:(OC技巧,ios,block)