标签:reactive
上一篇文章作为开门篇讲述了Cocoa Reactive概述。
这里我们详细介绍一下CocoaReative在代码中的应用。
网上好多blog有人形容CocoaReative 中 signals是插座或者水龙头,感觉不是很好理解。我举个更贴近生活的,用电话订菜(餐馆是Signals,电话订阅是SubScriberNext)。
Create一个Signal我们视为是一个支持电话订餐的餐馆,他们有很多菜,油盐酱醋就更不用说,当一个电话打进来首先,这个Signal就开始执行,等菜做好了,菜馆要做的是SendNext通知你一下,你呢?就出来拿,或者让他们送来,最后吃掉。分析一下在这期间,可能会有好多订阅者,菜馆只有一个,厨师会源源不断的炒菜(不要说什么如果菜馆没菜怎么办?太坑了),满足所有订阅者(电话预定)的需求。当然如果没人订阅这些配菜不会被炒,都处于配菜状态,所以,这些配菜可以用来组合,过滤什么的,以达到满足用户的口味(SubscriberNext)。怎么样这个举例不知道能否帮助你的理解。
后面的讲述将会拆解步骤来辅助大家理解不同的功能和类、方法。
    //我是菜馆,有了我你们才有源源不断的饭菜可以吃
    RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        return nil;
    }];
    
    //有菜馆的菜单了,开始电话预定
    [signal subscribeNext:^(id x){
        NSLog(@"客户处理开始吃了:X是菜馆给的%@",x);
    }];
如果菜馆没有接到电话约定是不是生意很冷啊,所以叫做冷信号。如果不停的接单是不是生意红火啊,叫(红火不就是热吗)做热信号。那放到程序中怎么理解:
    //我是菜馆,有了我你们才有源源不断的饭菜可以吃
    RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        //完成
        [subscriber sendCompleted];
        return nil;
    }];
    
    //如果后面没有订单我的生意怎么做啊!上面已经说了,如果没有订单我的生意怎么做,这就是冷Signal。
突然有一天,来生意了,结果来了一百个。是不是就火了,这就是热Signal。
    //来生意了
    //有菜馆的菜单了,开始电话预定
    [signal subscribeNext:^(id x){
        NSLog(@"客户处理开始吃了");
    }];
到这里不知道到家是否有对Signal有个初步的认识,Signal是Reactive的核心,理解了,基本上你就可以驾驭这个框架做你想做的。它不仅仅有SendNext方法,还有
sendNext:其实生活中菜馆是把所有的菜做好了,才打电话通知你,程序中是这样的,超好一个菜就sendNext:客户就吃一个。明白了很像在饭店吃饭(对,就是这样,你就理解是在饭店吃饭(执行Signal),做好一个上一个(SendNext),你吃一个(subscribeNext:))。
sendError: 这个就不用说了,肯定是不好意思,给你炒菜炒错了,现实中,你会想算了,吃吧(是你对错误的处理方式),这个方式只能执行一次(要是多长你还不要了厨师的命啊)。
sendComplete:这个也是执行一次,结账走人了。
    //执行一次
    [signal subscribeCompleted:^{
        NSLog(@"结账走人");
    }];
    
    //执行一次
    [signal subscribeError:^(NSError *error) {
        NSLog(@"算了,人家做生意也不容易,将就吃吧");
    }];    //我是菜馆,有了我你们才有源源不断的饭菜可以吃
    RACSignal *signal = [[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        //完成
        [subscriber sendCompleted];
        return nil;
    }] doNext:^(id x) {
        NSLog(@"给点一次筷子什么的,米饭啊");
    }];
    <pre name="code" class="html">    //有菜馆的菜单了,开始电话预定 [signal subscribeNext:^(id x) { NSLog(@"客户处理开始吃了"); }];
       doNext 是在信号被处理前,做一些同步修饰工作,比如说送一次性筷子,哈哈,比如你在登陆Signal送出去后,你希望按钮(或者转菊花)现实登陆中....,都可以在这里做掉的。
菜馆在做菜的时候肯定都是配好菜的,之后把这些配菜组合过滤,就变成了我们想吃的菜,有人问如何过滤?你喜欢吃香菜吗?喜欢辣椒吗?喜欢大蒜吗?这回知道了吧?那如何反映到Reactivie中呢?
    RACSignal *signal = [[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        //完成
        [subscriber sendCompleted];
        return nil;
    }] filter:^BOOL(id value) {                    //-----------------------------------------新增代码
        //过滤辣椒   
        BOOL noLaJiao = YES;
        NSLog(@"过滤辣椒");
        return noLaJiao;
    }] doNext:^(id x) {
        NSLog(@"给点一次筷子什么的,米饭啊");
    }];
    
    //订单-<span style="font-family: Arial, Helvetica, sans-serif;">--------------------------------------------------------------如果noLaJiao=NO;你会吃吗?</span>
    [signal subscribeNext:^(id x) {
        NSLog(@"客户处理开始吃了");
    }];上面代码有什么不同,你一眼就看出来,过滤辣椒,你可以把这个代码copy过去运行一下,你把noLaJiao改成NO试试,你看看订单那部分代码会执行吗?你会吃吗?肯定不会的。这就是过滤filer字面意思你也理解了。
这个地方注意一下他是返回的BOOL值,但是如果我们需要是数据,我们就需要map一次进行数据整合(辣椒给你过滤,菜还要给你做,做好了好吧菜端出去)。
    RACSignal *signal = [[[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        //完成
        [subscriber sendCompleted];
        return nil;
    }] filter:^BOOL(id value) {
        //过滤辣椒
        BOOL noLaJiao = YES;
        NSLog(@"过滤辣椒");
        return noLaJiao;
    }] map:^id(id value) {
        NSLog(@"菜加工中......");//-------------------------------------新增代码  这个地方开始加工菜了
        return value;
    }] doNext:^(id x) {
        NSLog(@"给点一次筷子什么的,米饭啊");
    }];
    
    //订单
    [signal subscribeNext:^(id x) {
        NSLog(@"客户处理开始吃了");
    }];2015-02-02 17:08:37.816 TestRAC[5863:192403] 接单了 2015-02-02 17:08:37.816 TestRAC[5863:192403] 处理..... 2015-02-02 17:08:39.649 TestRAC[5863:192403] 过滤辣椒 2015-02-02 17:08:41.016 TestRAC[5863:192403] 菜加工中...... 2015-02-02 17:08:42.017 TestRAC[5863:192403] 给点一次筷子什么的,米饭啊 2015-02-02 17:08:42.873 TestRAC[5863:192403] 客户处理开始吃了
    @weakify(self);   //--------------------------------1
    RACSignal *signal = [[[[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        //完成
        [subscriber sendCompleted];
        return nil;
    }] filter:^BOOL(id value) {
        //过滤辣椒
        BOOL noLaJiao = YES;
        NSLog(@"过滤辣椒");
        return noLaJiao;
    }] map:^id(id value) {
        NSLog(@"菜加工中......");
        return value;
    }] flattenMap:^RACStream *(id value) {  <span style="font-family: Arial, Helvetica, sans-serif;">//--------------------------------2</span>
        NSLog(@"我才没鸡了,你怎么不早说....赶紧买鸡去.....");
        @strongify(self);//-------------------------------------------------------------3
        [self performSelector:@selector(buyChicken) withObject:nil afterDelay:3];//---------------------------4
        return [[[self rac_signalForSelector:@selector(buyChicken)] filter:^BOOL(id value) {
            BOOL goodChinken=YES;//-----------------------------5
            return goodChinken;
        }] map:^id(id value) {
            return @"买到好鸡了....是白羽鸡......";
        }];
    }] doNext:^(id x) {
        NSLog(@"给点一次筷子什么的,米饭啊");
    }];
    
    //订单
    [signal subscribeNext:^(id x) {
        NSLog(@"客户处理开始吃了-%@",x);
    }];- (void) buyChicken
{
    NSLog(@"买鸡回去.....买回来了......");
}2015-02-02 17:28:52.688 TestRAC[5968:201097] 接单了 2015-02-02 17:28:52.689 TestRAC[5968:201097] 处理..... 2015-02-02 17:28:54.777 TestRAC[5968:201097] 过滤辣椒 2015-02-02 17:28:55.992 TestRAC[5968:201097] 菜加工中...... 2015-02-02 17:28:55.992 TestRAC[5968:201097] 我才没鸡了,你怎么不早说....赶紧买鸡去..... 2015-02-02 17:29:02.104 TestRAC[5968:201097] 买鸡回去.....买回来了...... 2015-02-02 17:29:09.279 TestRAC[5968:201097] 给点一次筷子什么的,米饭啊 2015-02-02 17:29:10.911 TestRAC[5968:201097] 客户处理开始吃了-买到好鸡了....是白羽鸡......
2行代码是对信号依赖的处理,关键字flattenMap。
3模拟买鸡过程用时3秒钟。
4这个是NSObject一个累扩展,这里先不讲,意思说产生一个信号,等信号触发后返回买鸡信号。如果你看不懂你可以这么做:
5就不说了,看一下4改进的代码:
    //买鸡信号
    RACSignal *buyChinkenSignal = [[[self rac_signalForSelector:@selector(buyChicken)] filter:^BOOL(id value) {
        BOOL goodChinken=YES;
        return goodChinken;
    }] map:^id(id value) {
        return @"买到好鸡了....是白羽鸡......";
    }];
    
    @weakify(self);
    RACSignal *signal = [[[[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        NSLog(@"接单了");
        NSLog(@"处理.....");
        [subscriber sendNext:@"炒菜完成,打电话给客户"];
        //完成
        [subscriber sendCompleted];
        return nil;
    }] filter:^BOOL(id value) {
        //过滤辣椒
        BOOL noLaJiao = YES;
        NSLog(@"过滤辣椒");
        return noLaJiao;
    }] map:^id(id value) {
        NSLog(@"菜加工中......");
        return value;
    }] flattenMap:^RACStream *(id value) {
        NSLog(@"我才没鸡了,你怎么不早说....赶紧买鸡去.....");
        @strongify(self);
        [self performSelector:@selector(buyChicken) withObject:nil afterDelay:3];
        
        //------------------------------------买鸡信号--------------------------------
        return buyChinkenSignal;
    }] doNext:^(id x) {
        NSLog(@"给点一次筷子什么的,米饭啊");
    }];
好长.....后面在总结........
不同信号组合和控件的使用,信号数据Sequence等。
标签:reactive
原文地址:http://blog.csdn.net/folish_audi/article/details/43408863