昨天看了一篇文章,http://www.jianshu.com/p/87ef6720a096,感觉里面对链式编程和函数式编程总结得挺不错,,对此我总结和补充一下。
一.链式编程:
现在主流的布局所使用的masonry就是用这种方式来进行的,,首先说说链式编程的特点:
1.链式编程的目标对象的返回值是一个block。
2.block的参数为你要操作的内容,,这里一般是该对象的属性
3.block一般豆有返回值,,并且返回值是对象本身。
这里看这些可能还无法理解,,所以现在直接上代码
一 。首先定义一个可以进行加减乘除的对象CaculatorMaker,给其一个属性result,,这里所要操作的内容就是这个对象的result属性
这里直接给出加法的实现方式 ,其余的算法跟加法类似
- (CaculatorMaker * (^)(int))add {
return ^CaculatorMaker *(int value) {
_result += value ;
}
}
二。定义一个生成CaculatorMaker对象的nsobject对象的类别CaculatorManager .这个对象主要是生成CaculatorMaker的 。
+ (int)makeCaculators:(void(^)(CaculatorMaker *make))block {
CaculatorMaker *ctm =[ [CaculatorMaker alloc] init] ;
block(ctm) ;
return ctm.result ;
}
这里实现的block(ctm)里面的实现是对ctm的result对象的各种操作.
三。调用:
int result = [NSObject makeCaculators:^(CaculatorMaker *make) {
make.add(2).add(4).add(8) ;
}]
这个result就是其最后的结果.由于CaculatorMaker对象的初始化值为默认的0 。所以这里最后的结果为14 。
这里就是总结的链式编程的思想
下面再来介绍一下函数式编程:
首先说说函数式编程的特点:
1.函数式编程里面的函数的返回值为自身。
2.函数式编程的参数为block。
3.block的对象为所要操作的数据,,这里通常是该对象的某个属性
这里给出一个需求:判断2*5是否等于10 。
一。首先定义一个计算对象Caculator .,给其一个属性result,,这里所要操作的内容就是这个对象的result属性,一个是否相等的属性isEqual .
实现这个类的计算方法和比较fang发:
- (Caculator *)calculator:(int (^)(int result))calculator {
_result = calculator(_result) ;
return self ;
}
- (Calculator *)equal:(BOOL (^)(int result))operation {
_isEqual = operation(_result) ;
return self ;
}
二.调用:
Calculator *c = [[Caculator alloc] init] ;
BOOL isEqual = [[[c calculator:^(int result) {
return (result+2)*5 ;
}] equal:^(int result) {
return result == 10 ;
}] isEqual] ;
这里函数式编程和链式编程暂时就讲到这了。如果还需补充的望请批评和改正
下面再来说说ReactiveCocoa.
这里主要来说说ReactiveCocoa里面的几个类和几个替代原有的oc语法的几个实例。
首先将将信号类(RACSign),这个是ReactiveCocoa里面的核心和基础.
一 。首先生成RACSign
RACSignal *sign = [RACSignal createSignal:^RACDisposable *(idsubscriber) {
NSLog(@"发送请求");
//这里如果没有发送请求,,那么这个信号将一直是冷信号,,其不会激活所订阅的信号
[subscriber sendNext:@"2"] ;
//这里是数据传输完成之后,使用sendcompleted,这是命令才执行完毕
[subscriber sendCompleted] ;
return nil ;
}] ;
二 。订阅信号
[sign subscribeNext:^(id x) {
//这里的x是上面所发送的数值2.
NSLog(@"接收到该数据") ;
}] ;
这个是sign的简单的实现.
接下来我们将将RACSubject ,RACReplaySubject这两个对象
RACSubject对象的实现步骤主要是这三部:定义,订阅,发送(激活) .
一。定义。
RACSubject的定义非常简单直接使用subject的类方法就行
RACSubject *subject = [RACSubject subject] ;
二,订阅:
调用subject的subscribeNext方法,,这里可以有多个订阅者
//第一个订阅者
[subject subscribeNext:^(id x) {
NSLog(@"这个是第一个订阅者>>%@",x) ;
}] ;
//第二个订阅者
[subject subscribeNext:^(id x) {
NSLog(@"这个是第二个订阅者>>%@",x) ;
}] ;
三,依次激活所有的订阅者
[subject sendNext:@"1"] ;
RACReplaySubject的用法和RACSubject的用法基本上很类似。。不同点在于
1.RACReplaySubject可以先激活再订阅
2.RACReplaySubject可以用不同的值去激活
这里直接贴代码:
RACReplaySubject *replaySubject = [RACReplaySubject subject] ;
[replaySubject sendNext:@"2"] ;
[replaySubject sendNext:@"3"] ;
[replaySubject subscribeNext:^(id x) {
NSLog(@"订阅者%@",x) ;
}] ;
[replaySubject subscribeNext:^(id x) {
NSLog(@"订阅%@",x) ;
}] ;
接下来讲讲RACCommand这个类
这里RACCommand的步骤主要如下:
1.创建命令
2.创建信号用来传递数据
3.订阅RACCommand中的信号
4.执行命令
这里直接贴出代码:
//1.创建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@"执行命令") ;
// return [RACSignal empty] ;
//2.创建信号,
用来传递数据 return [RACSignal createSignal:^RACDisposable *(idsubscriber) {
[subscriber sendNext:@"请求数据"] ;
//数据传递完,最好调用sendCompleted,这时命令才执行完毕 .
[subscriber sendCompleted] ;
return nil ;
}] ;
}] ;
_command = command ;
//3.订阅RACCommand中的信号
[command.executionSignals subscribeNext:^(id x) {
[x subscribeNext:^(id x) {
NSLog(@"x is %@",x) ;
}] ;
}] ;
//监听命令是否执行完毕,默认会执行一次,可以直接跳过,skip表示跳过第一次信号
[[command.executing skip:1] subscribeNext:^(id x) {
if ([x boolValue]) {
//正在执行
NSLog(@"正在执行") ;
}else {
//执行完成
NSLog(@"执行完成") ;
}
}] ;
}
然后再去要调用的时候执行[_command execute:@1] ;即可激活这个命令
接下来讲讲用RACSubject来传值
这里假设有两个vc:ViewController和SecondViewController
1.首先在SecondViewController中定义一个RACSubject对象delegateSign ;
2.在ViewController中去订阅这个信号:
SecondViewController *secondCtr = [[SecondViewController alloc] init] ;
secondCtr.delegateSignal = [RACSubject subject] ;
//订阅信号
[secondCtr.delegateSignal subscribeNext:^(id x) {
NSLog(@"当前页面需要做的回应") ;
}] ;
[self.navigationController pushViewController:secondCtr animated:YES] ;
3.在SecondViewController中恰当的位置去激活这个信号。
if (self.delegateSignal) {
[self.delegateSignal sendNext:nil] ;
}
这样既可以不需要注册通知(以防多次注册),也不需要自己去写代理(太为复杂,可读性差),也不需要自己去写block(整不好会有内存泄漏).然后就这么轻松的就实现了
接下来讲讲替代oc里面的通用方法:
一。代理:
1.定义一个视图,,这里用原作者的视图名称RedView,,视图中有个按钮,,在本视图中的点击事件为clickTheRedButton
2,直接食用rac_SignForSelector方法和subscribeNext方法去写代理
[[redV rac_signalForSelector:@selector(clickTheRedButton)] subscribeNext:^(id x) {
NSLog(@"这个页面点击了按钮的代理") ;
}] ;
二。kvo
这个就更简单了,,直接使用
ran_valuesAndChangesForKeyPath : options:和subscribeNext方法即可
[[redV rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
//这个x是RACTuple对象
NSLog(@"x is %@",x) ;
}] ;
3.通知代替
使用rac_addObserverForName和subscribeNext方法即可
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"键盘弹出");
}];
4.处理多个请求:
// 6.处理多个请求,都返回结果的时候,统一做处理. RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(idsubscriber) { // 发送请求1 [subscriber sendNext:@"发送请求1"]; return nil; }]; RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(idsubscriber) {
// 发送请求2
[subscriber sendNext:@"发送请求2"];
return nil;
}];
// 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。
[self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
// 更新UI
- (void)updateUIWithR1:(id)data r2:(id)data1
{
NSLog(@"更新UI%@ %@",data,data1);
}