- 先来看一段代码:
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/-