链式编程,函数式编程和ReactiveCocoa

昨天看了一篇文章,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);

}

你可能感兴趣的:(链式编程,函数式编程和ReactiveCocoa)