链式编程和函数式编程

  • 先来看一段代码:
    Person *person1 = [[Person alloc] init];
    [person1 run1];
    [person1 eat1];

这段代码说明:定义了一个Person类,提供了一个run方法和一个eat方法
方法声明:

- (void)run1;
- (void)eat1;

方法实现:

- (void)run1{
    NSLog(@"跑步1");
}
- (void)eat1{
    NSLog(@"吃饭1");
}

这种方式正是我们开发中最常使用的方式,缺点:
1.方法需要单独调用
2.不能随意组合顺序

  • 接下来再来看一段代码:
    UIView *view = [[UIView alloc] init];
    [self.view addSubview:view];
    
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.mas_equalTo(self.view).mas_offset(0);
        make.top.mas_equalTo(self.view).mas_offset(80);
        make.height.mas_equalTo(100);
    }];

这里使用了Masonry对控件进行布局,OC中的对象调用方法时的格式一般为:
[对象 对象方法:参数1,参数2]
而Masonry约束的这段代码中,使用了()的方式设置参数,使用.的方式同时调用多个方法

Masonry中正是使用了函数式编程与链式编程的方式

__函数式编程特点: __使用 "()" 替代OC中的 "[]"

链式编程的特点:一行代码一级一级的调用方法

除了Masonry,另一款开源自动布局框架PureLayout中,也正是使用了这种编程方式,让代码闲的更精练易懂

  • 实现链式编程

如果实现链式调用呢? 首先从代码入手分析:

目标:   [[person eat1]run1];
                ↓
                ↓
        Person *person = [person eat1]; 
        [[person eat1] run1];

由此可见,只需要让每个方法都有个instancetype的返回值即可
接下来就模仿这种编程方式,将run和eat方法进行改进

方法声明:

- (Person *)run2;
- (Person *)eat2;

方法实现:

- (Person *)run2{
    NSLog(@"跑步2");
    return self;
}
- (Person *)eat2{
    NSLog(@"跑步2");
    return self;
}

这样再来调用看一下效果

    Person *person2 = [[Person alloc] init];
    [[[[person2 run2] eat2] run2] eat2];

目前来,链式编程调用的方式是暂时实现了

  • 实现函数式编程

如何实现链式调用呢?首先需要思考,如何调用函数时使用小括号,OC中常用到小括号的场景有哪些? --> block

     // block声明
     void (^Myblock)() = ^{
        NSLog(@"block");
     }
     // block调用
     Myblock();

所以第一步,将方法返回值类型改为一个void(^)()类型

方法声明:

- (void (^)())run3;
- (void (^)())eat3;

方法实现:

- (void (^)())run3{
    
    void (^MyBlock)() = ^{
        NSLog(@"跑步3");
    };
    
    return MyBlock;
}
- (void (^)())eat3{
    
    // 在run3的基础上,将block的定义和返回合并
    return ^{
        NSLog(@"吃饭3");
    };
}

调用效果:

    Person *person3 = [[Person alloc] init];
    person3.eat3();
    person3.run3();

目前来看调用方法时使用小括号的效果实现了,如何结合链式调用呢?

结合实现链式编程的方法,我们现在返回值类型是一个无参无返回值类型的block,如果让block的返回值类型为instanceType是不是就可以了呢?

继续改动代码

方法声明:

- (Person * (^)())run4;
- (Person * (^)())eat4;

方法实现:

- (Person * (^)())run4{

    Person * (^MyBlock)() = ^{
        
        NSLog(@"跑步4");
        return self;
    };
    
    return MyBlock;
}
- (Person * (^)())eat4{
    
    return ^{
        NSLog(@"吃饭4");
        return self;
    };
}

再来看一下调用效果:

    Person *person4 = [[Person alloc] init];
    person4.eat4().eat4().run4().eat4();

这样就实现了函数式编程和链式编程

接下来,如果需要传递参数,相信大家也就都会了,只需要设置Block参数即可

Person类示例代码
.h:

#import <Foundation/Foundation.h>

@interface Person : NSObject

#pragma mark -- 最常见的写法
- (void)run1;
- (void)eat1;

#pragma mark -- 链式编程
- (Person *)run2;
- (Person *)eat2;

#pragma mark -- 函数式编程步骤1 -> 调用方法使用小括号
- (void (^)())run3;
- (void (^)())eat3;

#pragma mark -- 函数式编程步骤2 --> 链式调用多个方法
- (Person * (^)())run4;
- (Person * (^)())eat4;

#pragma mark -- 函数式编程步骤3 --> 传递参数
- (Person * (^)(double distance))run5;
- (Person * (^)(NSString *kindOfFood))eat5;

@end

.m:

#import "Person.h"

@implementation Person

#pragma mark -- 最常见的写法
- (void)run1{
    NSLog(@"跑步1");
}
- (void)eat1{
    NSLog(@"吃饭1");
}

#pragma mark -- 链式编程
- (Person *)run2{
    NSLog(@"跑步2");
    return self;
}
- (Person *)eat2{
    NSLog(@"跑步2");
    return self;
}

#pragma mark -- 函数式编程 1
- (void (^)())run3{
    
    void (^MyBlock)() = ^{
        NSLog(@"跑步3");
    };
    
    return MyBlock;
}
- (void (^)())eat3{
    
    // 在run3的基础上,将block的定义和返回合并
    return ^{
        NSLog(@"吃饭3");
    };
}

#pragma mark -- 函数式编程 2
- (Person * (^)())run4{

    Person * (^MyBlock)() = ^{
        
        NSLog(@"跑步4");
        return self;
    };
    
    return MyBlock;
}
- (Person * (^)())eat4{
    
    return ^{
        NSLog(@"吃饭4");
        return self;
    };
}

#pragma mark -- 函数式编程 3
- (Person *(^)(double))run5{
    return ^(double distance){
        NSLog(@"跑了%.2f米",distance);
        return self;
    };
}
- (Person *(^)(NSString *))eat5{
    return ^(NSString *kindOfFood){
        NSLog(@"吃了%@",kindOfFood);
        return self;
    };
}

@end

使用函数式编程和链式编程对于封装框架和阅读第三方开源框架有很大帮助
代码连接:https://github.com/ShenYj/-

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容