iOS之block的多种使用

197 阅读6分钟

block想必大家都很熟悉了,这就不在啰嗦概念了,直接上重点;今天聊聊block在平时开发中的三种用法:1.作为属性;2.作为参数;3.作为返回值 这三种用法。说这之前先说下xcode中自带的block代码块 inlineBlock

image.png

void(^hhblock)(void) = ^() {
    NSLog(@"执行block");
};
hhblock();
打印结果
**2022-02-10 21:29:48.202772+0800 YTKRequestDemo[6629:289374] 执行block**

接下来给block添加返回值

int (^hhblock)(int a,int b) = ^(int a,int b) {
    NSLog(@"执行block");
    return a + b;
};
NSLog(@"%d",hhblock(10,20));
打印结果:
**2022-02-10 21:35:45.865788+0800 YTKRequestDemo[6752:294763] 执行block**
**2022-02-10 21:35:45.865966+0800 YTKRequestDemo[6752:294763] 30**
id (^hhblock)() = ^() {
    NSLog(@"执行block");
    NSString *str;
    return str;
};
hhblock();
打印结果:
**2022-02-10 21:37:53.805888+0800 YTKRequestDemo[6796:296565] 执行block**

这些都正常运行但是return nil 时报错了 image.png 这是因为block值不知道你返回nil是怎么类型,这是在开发中经常会被忽略导致的错误,正确的写法应该是

id (^hhblock)(void) = ^id() {
    NSLog(@"执行block");
    return nil;
};
hhblock();

切记在block值中写上返回值,这是我们可以把inlinkblock代码块修改下做成自己的代码块

<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = <#returnType#>^(<#parameters#>) {
    <#statements#>
};

这个是我曾经犯过的错误,在这里写出来记录下,也许有小伙伴和我一样犯过这种错误,也让看到的小伙伴记住这个点。 接下来我们进入正题

block 作为属性

首先我们定义一个Person类

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^pblock)(void);
@end

viewcontroller 中调用

- (void)viewDidLoad {
    [super viewDidLoad];
    _p = [[Person alloc]init];
    _p.run = ^{
        NSLog(@"我跑起来了");
    };
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    _p.run();
}
打印结果
**2022-02-10 22:19:01.811979+0800 YTKRequestDemo[7365:320911] 我跑起来了**

这是常见常用的一种方式,block作为属性。

blcok 作为参数

在person中定义一个方法

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^pblock)(void);
- (void)eat:(void(^)(void))block;
@end
#import "Person.h"
@implementation Person
- (void)eat:(void (^)(void))block{
    NSLog(@"在person中调用你的block");
    // 执行block
    block();
}
@end

viewcontroller 中调用

- (void)viewDidLoad {
    [super viewDidLoad];
    _p = [[Person alloc]init];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
   [_p eat:^{
        NSLog(@"我吃过饭了");
    }];
}
打印结果
**2022-02-10 22:32:31.444882+0800  在person中调用你的block**
**2022-02-10 22:32:31.445049+0800  我吃过饭了**

block 作为返回值

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^pblock)(void);
- (void)eat:(void(^)(void))block;
- (void)jump:(int)meter;
@end

调用jump方法

[_p jump:1];

这是简单的oc方法的调用方式,我现在在想还有其他调用方式吗?可不可以用点语言调用了,_p.jump();oc中的特性,get方法可以点出来,那接下来对代码进行修改

#import <Foundation/Foundation.h>
@interface Person : NSObject
- (int)jump;
@end
#import "Person.h"
@implementation Person
- (int)jump{
    NSLog(@"哥们我跳了");
    return 1;
}
@end
在viewController 中调用
_p.jump;
打印结果
**2022-02-10 23:00:22.588556+0800 YTKRequestDemo[8087:349861] 哥们我跳了**

这时候就是用点语法调用oc对象方法,做到这我在想怎么给方法中传递参数了? _p.jump 返回值是int,那把返回值改成block试试

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^run)(void);
- (void(^)(void))jump;// 返回一个无参数的block
@end
#import "Person.h"
@implementation Person
- (void (^)(void))jump{
    // 返回一个block
    return ^() {
        NSLog(@"我执行了");
    };
}
@end
viewController 中调用
// jump返回的是一个block,所以用block接收返回值
void(^jblock)(void) = _p.jump;
// 调用返回值block
jblock();
打印结果
**2022-02-10 23:08:16.528973+0800 YTKRequestDemo[8225:355730] 我执行了**

// block作为返回值是可行的,优化上面代码 _p.jump 返回的是个block,那可以直接优化为_p.jump();
_p.jump();
打印结果
**2022-02-10 23:14:01.390396+0800 YTKRequestDemo[8307:359088] 我执行了**

这时候就在想_p.jump();()括号中是可以用来传递参数的,()是block的,所以在返回值block中加入参数就可以

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^run)(void);
- (void(^)(int a))jump;// 返回一个无参数的block
@end
#import "Person.h"
@implementation Person
- (void (^)(int a))jump{
    // 返回一个block
    return ^(int a) {
        NSLog(@"我跳了%d米高",a);
    };
}
@end
viewController 中调用
_p.jump(1);
打印结果
**2022-02-10 23:17:37.761479+0800 YTKRequestDemo[8388:362375] 我跳了1米高**

这就是block作为返回值的用法;看到这种写法,大家应该想到了masonry了吧,masonry就是这样写的,但是masonry可以无限的点下去;那我们接着修改代码;分析:jump是对象p的方法,只有p能点出来,那_p.jump(1)执行完返回一个p对象,那就能继续执行下去了

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy) void(^run)(void);
- (Person *(^)(int a))jump;// 返回一个无参数的block
@end
#import "Person.h"
@implementation Person
- (Person *(^)(int a))jump{
    // 返回一个block
    return ^(int a) {
        NSLog(@"我跳了%d米高",a);
        return self;
    };
}
@end
viewController 中调用
_p.jump(1).jump(2).jump(3);
打印结果
**2022-02-10 23:23:59.868825+0800 YTKRequestDemo[8498:366488] 我跳了1米高**
**2022-02-10 23:23:59.869185+0800 YTKRequestDemo[8498:366488] 我跳了2米高**
**2022-02-10 23:23:59.869362+0800 YTKRequestDemo[8498:366488] 我跳了3米高**

完美实现了block最为返回值的使用方法;接下来发现一个问题

image.png 点出方法来没有要传参数的提示,继续修改

#import <Foundation/Foundation.h>
@class Person;
typedef Person *_Nullable (^PersonBlock)(int a);
@interface Person : NSObject
@property (nonatomic,copy) PersonBlock runblock;
@end
#import "Person.h"
@implementation Person
- (PersonBlock)runblock{
    // 返回一个block
    return ^(int a) {
        NSLog(@"我跳了%d米高",a);
        return self;
    };
}
@end
#import "Person.h"
@implementation Person
- (Person *(^)(int a))jump{
    // 返回一个block
    return ^(int a) {
        NSLog(@"我跳了%d米高",a);
        return self;
    };
}
@end
viewController 中调用
_p.runblock(1).runblock(2);
打印结果
**2022-02-10 23:35:33.596224+0800 YTKRequestDemo[8683:374134] 我跳了1米高**
**2022-02-10 23:35:33.596364+0800 YTKRequestDemo[8683:374134] 我跳了2米高**

image.png 把方法改成属性,在调用的时候就有了参数怎么传的提示了。 一直用点语法点下去这种方式叫链式编程

链式编程+block封装UIkit

最后我自己基于UIKit封装的基础控件库,使用链式编程思想+block对常用的控件进行封装,包含UIView,UILabel,UIButton,UITextFiled,UITextView,UITableView的封装HHBlockKit 欢迎大家下载看看,有问题一起讨论,小弟不才,咱们一起研究,若觉得对你有用请给个star😁。