商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > iOS链式编程及函数式编程

iOS链式编程及函数式编程

  发布于2026-07-21 阅读(0)

扫一扫,手机访问

提到链式编程和函数式编程,最典型的代表是Masonry,它比较完美地实现了这两种编程风格。例如:

[view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.view).offset(100);
    make.centerX.equalTo(self.view.mas_centerX).offset(100);
    make.height.mas_equalTo(100);
    make.width.mas_equalTo(100);
}];复制代码

所谓的链式编程,说白了就是在返回值的基础上继续调用方法。那么问题来了:什么样的返回值才能继续调用方法?答案很简单——返回对象。只要返回一个对象,然后继续调用该对象的对象方法,就能实现链式编程。

举个简单的例子:先定义一个Person类,添加两个对象方法:

-(void)play;
-(void)run;复制代码
-(void)play{
    NSLog(@"play");
}
-(void)run{
    NSLog(@"run");
}复制代码

ViewController中调用:

Person * xiaoming = [Person new];
[xiaoming play];复制代码

现在我们想要实现的是 [[xiaoming play]run],所以 play 方法的返回值就不能为空,应该返回 Person 对象:

-(Person *)play;
-(Person *)play{
    return self;
}复制代码

这样一来,[[xiaoming play]run] 就顺利实现了。

不过,这种链式编程和 Masonry 相比还是差了点意思。我们知道在 OC 中,方法调用是通过发送消息的方式实现的,那么要实现 person.eat 这种点语法该怎么处理?

-(void(^)(void))play2;复制代码
-(void (^)(void))play2{
    return ^(){
        NSLog(@"play2");
    };
}复制代码

这样就能实现 [xiaoming play].play2(); 了。

如果后续还想继续添加点方法,思路相同,只需要让返回值始终是 Person 对象即可:

-(Person *(^)(NSString * str))play2;
-(void(^)(NSString * str))play3;复制代码
- (Person *(^)(NSString *str))play2{
    return ^(NSString *str){
        NSLog(@"%@",str);
        return self;
    };
}
-(void (^)(NSString * str))play3{
    return ^(NSString * str){
        NSLog(@"%@",str);
    };
}复制代码

这样就能实现 xiaoming.play2(@"33").play3(@"333"); 这种连续调用。

上面的方法本质是通过 block 返回当前对象,从而实现点语法连续调用。

构造方法

函数式编程,就是通过类似函数调用的方式来实现想要的功能,即 method(); 这样的形式。在 OC 中,能用 method() 这种形式调用的,只有 block。我们在调用 block 时不就是这么写的吗?所以,只要一个方法的返回值是 block,就可以使用函数式调用。

定义构造方法:

+(instancetype)initWithP:(void(^)(Person * p))Block;复制代码
+(instancetype)initWithP:(void (^)(Person *))Block{
    Person * p = [Person new];
    return p;
}复制代码

可以调用返回值为 p 的函数式构造方法,然后在内部对 p 对象进行操作:

[Person initWithP:^(Person *p) {}];复制代码

这样就可以调用链式方法了:

[Person initWithP:^(Person *p) {
    p.play2(@"222").play3(@"3333");
}];复制代码

定义成员属性实现点语法

上面都是通过定义方法来实现点语法调用,但我们的编程习惯通常是用点语法来调取类的成员属性。OC 的点语法中,.XX 是 getter,.XX=XXX 是 setter。显然链式编程是一串连续的调用,所以应该想到把 block 声明为属性,并在这些 block 属性的 getter 方法中做些事情。

Person 类中添加成员属性:

@property(nonatomic,readonly,copy)Person *(^eat)(NSString * str);复制代码

重写成员属性的 getter 方法:

-(Person *(^)(NSString *))eat{
    return ^(NSString* eat){
        NSLog(@"%@",eat);
        return self;
    };
}复制代码

这样就能用点语法调用 eat 方法了:

[Person initWithP:^(Person *p) {
    p.play2(@"222").eat(@"333").play3(@"444");
}];复制代码

定义属性相比定义方法,一个突出的优点就是输入时会有代码提示,所以更常用。

举例说明:

现在我们要在 VC 上添加四个大小相同、圆角为 2 的红色 view,实现代码如下:

@interface MYView : UIView
+(instancetype)initWith:(void(^)(MYView *view))BLOCK;
@property(nonatomic,readonly,copy)MYView *(^viewFrame)(CGRectframe);
@property(nonatomic,readonly,copy)MYView * (^layerCornerRadious)(CGFloat radious);
@property(nonatomic,copy,readonly)MYView*(^ColorString)(NSString * colorStr);
@end复制代码
+(instancetype)initWith:(void (^)(MYView *))BLOCK{
    MYView * view = [[MYView alloc]init];
    if (BLOCK) {
        BLOCK(view);
    }
    return view;
}
-(MYView *(^)(CGRect))viewFrame{
    return^MYView*(CGRect rect){
        self.frame = rect;
        return self;
    };
}
-(MYView *(^)(CGFloat))layerCornerRadious{
    return ^MYView*(CGFloat radious){
        self.layer.cornerRadius = radious;
        self.layer.masksToBounds = YES;
        return self;
    };
}
-(MYView *(^)(NSString *))ColorString{
    return ^MYView* (NSString * colorStr){
        self.backgroundColor = [UIColor redColor];
        return self;
    };
}复制代码

在 VC 中只需调用:

[self.view addSubview:[MYView initWith:^(MYView *View) {
    View.viewFrame(CGRectMake(100, 200, 20, 20)).layerCornerRadious(2).ColorString(@"颜色自己设置");
}]];复制代码
本文转载于:https://blog.csdn.net/weixin_33813128/article/details/91422604 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注