HWWY

导航

ReactiveCocoa的学习内容

ReactiveCocoa

知识备用库:iOS10 collectionView以前是复用的,但是iOS10以后就要设置一个属性才可以复用。

C语言面向过程编程,OC面向对象编程

链式编程思想(masonry),可读性特别好,聚合度高;

响应式编程思想(KVO),解耦比较好;

函数式编程结构 + 响应式编程思想 = ReactiveCocoa 的实现;

所谓的店语法无非是get或者set方法,set方法一般用于赋值,get方法一般用于取值

关于OC中的括号传递参数的思想其本质就是block,当想用链式编程思想的时候第一个想到的就是block。下面是一个简单的例子:

```

-(void(^)())testCode

{

    NSLog(@"======a");

    void(^block)() = ^{

        NSLog(@"======c");

    };

    

    NSLog(@"======b");

    return block;

}

调用后的输出的结果为:

2018-02-05 15:54:02.660583<0800 RACtest[1138:36428] ======a

2018-02-05 15:54:02.660738>0800 RACtest[1138:36428] ======b

2018-02-05 15:54:02.660823+0800 RACtest[1138:36428] ======c

```

 

---

```

   ^{

        //其实这里你可以把代码可以全部保存到这里

        NSLog(@"保存你的代码");

    }();

```

备注:其实上面的这种代码格式为了更好的管理代码,没别的意思

下面我就用这种链式编程思想实现一个简单的加法计算器,仿照Masonry,首先我在这里定义了一个 CalculateManager的类,然后在里面用block实现链式调用的这种方法

```

typedef CalculateManager *(^CalculateManagerBlock)(NSInteger value);

-(CalculateManagerBlock)add

{

    return ^(NSInteger value){

        _result += value;

        return self;

    };

}

```

上面的这种思想我觉得在封装SDK的时候真心是一个不错的选择,但是你知道这个函数的执行顺序吗,首先调用函数方法,然后调用block,记住这个参数不是函数本身的参数,而是block的,调用()之心里面的 ^{}里面的代码,然后在block里返回CalculateManager。

上面是RAC的基础下面进入正题:

先说下KVO,其实KVO是属于响应式编程思想的一种,KVO底层的原理是监听set方法有没有调用,KVO只能监听set方法。KVO的实现原理,(1)动态生成子类,也叫派生类(子类会继承所有的父类的方法);(2)生成子类为了重写父类的set方法,目的监听属性有没有改变;(3)修改对象的isa指针,isa指向那个类就去那个类中查找方法,IPM-指向实际执行函数体的函数指针,_cmd SEL 类型的一个变量,Objective C的函数的前两个隐藏参数为self 和 _cmd,ivar ivar - objective C中的实例变量。

RAC有两个版本一个是OC的,另外一个是swift的,默认是swift版本的,如果想要OC版本的用 ReactiveObjC 搜索。

在这里任何事情都通过信号传递,当然新框架的学习也是非常困惑的,我们一般时候学习的时候通常在一般的常用的类入手,其次想着框架的实现和源码的阅读,对于RAC来说,在代码的实现是函数式,其思想是响应式编程。

RACSignal:基础的类

RACDisposable:处理数据

RACSubscriber:订阅者

RAC注意点,在信号订阅的时候不要订阅多次,不要分开订阅,下面是关于RAC的执行流程

//如何事件都是信号,信号需要去订阅(可以理解为绑定)

信号的订阅简单的实现(方法1)

```

    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        NSLog(@"=======执行1");

        [subscriber sendNext:@2];

        [subscriber sendCompleted];

        return [RACDisposable disposableWithBlock:^{

            //清空数据

            NSLog(@"=======执行5");

        }];

    }];

    

    [signal subscribeNext:^(id  _Nullable x) {

        NSLog(@"=======执行2");

    } error:^(NSError * _Nullable error) {

        NSLog(@"=======执行3(并行执行)");

    } completed:^{

        NSLog(@"=======执行3");

    }];

```

输出结果:

```

2018-02-05 21:34:04.154012<0800 RACtest[891:27500] =======执行1

2018-02-05 21:34:04.154145>0800 RACtest[891:27500] =======执行2

2018-02-05 21:34:04.154282<0800 RACtest[891:27500] =======执行3

2018-02-05 21:34:04.154384>0800 RACtest[891:27500] =======执行5

```

想订阅多次的话可以用下面的方法代替上面的流程(方法二)

```

RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        NSLog(@"=======执行1");

        [subscriber sendNext:@2];

        [subscriber sendCompleted];

        return [RACDisposable disposableWithBlock:^{

            //清空数据

            NSLog(@"=======执行5");

        }];

    }];

    

    //订阅信号传值

    [signal subscribeNext:^(id  _Nullable x) {

        NSLog(@"=======subscribeNext");

    }];

 

    //订阅信号的错误信息

    [signal subscribeError:^(NSError * _Nullable error) {

        NSLog(@"=======subscribeError");

    }];

    

    //信号完成

    [signal subscribeCompleted:^{

        NSLog(@"=======subscribeCompleted");

    }];

```

输入结果:

```

2018-02-05 21:36:40.271006<0800 RACtest[958:29805] =======执行1

2018-02-05 21:36:40.271150>0800 RACtest[958:29805] =======subscribeNext

2018-02-05 21:36:40.271328<0800 RACtest[958:29805] =======执行5

---------------------------------------------------------------

 

2018-02-05 21:36:40.271509>0800 RACtest[958:29805] =======执行1

2018-02-05 21:36:40.271605<0800 RACtest[958:29805] =======执行5

---------------------------------------------------------------

 

2018-02-05 21:36:40.271804>0800 RACtest[958:29805] =======执行1

2018-02-05 21:36:40.271981<0800 RACtest[958:29805] subscribeCompleted=======

2018-02-05 21:36:40.272084>0800 RACtest[958:29805] =======执行5

```

上面都能实现信号的订阅,但是方法1的 block 会多次   =======执行1和 =======执行5

RACSubject 先订阅然后可以发送和上一个 RACSignal 完全不同,这个类订阅多次然后发送的时候一起执行订阅者的信息。

```

RACSubject *subject = [RACSubject subject];

    

    [subject subscribeNext:^(id  _Nullable x) {

        NSLog(@"订阅者1");

    }];

    

    [subject subscribeNext:^(id  _Nullable x) {

        NSLog(@"订阅者2");

    }];

    

    [subject sendNext:@1];

```

输出打印信息: 

```

2018-02-05 21:53:50.012831<0800 RACtest[1044:37676] 订阅者1

2018-02-05 21:53:50.012988>0800 RACtest[1044:37676] 订阅者2

```

以上都是先订阅后发送信号

下面是一个先发送后订阅的一个类

RACReplaySubject 继承自 RACSubject 

```

  RACReplaySubject *reSubject = [RACReplaySubject subject];

    [reSubject sendNext:@"====1"];

    [reSubject sendNext:@"====2"];

    [reSubject subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

   }];

```

输出结果:

```

2018-02-05 21:59:14.855276<0800 RACtest[1076:40729] ====1

2018-02-05 21:59:14.855430>0800 RACtest[1076:40729] ====2

```

关于RAC的类 RACSubject 在开发中的应用,可以代替代理,如果有这样一个需求,在VC上点击几个 view 视图 ,每点击一个就执行一次订阅者,还有一个需求就是我点击了 view 点击无论多少次只是执行一次 订阅,对于 RACSubject来说只是你调用 sendNext 和 sendCompleted的选择,感觉特爽,再也不用判断各种状态了;后者只需要调用 sendNext 和 sendCompleted,前者调用 sendNext 就可以实时的获取到状态。

 

 

=======================第一天结束====================

 

开启异步做一些事情处理数据,关于tableView的数据模型很复杂的时候可以开启异步线程再去刷新表格。

RAC的集合:处理数据在子线程中,异步线程处理数据,一般OC的数据类型转为RAC的集合的方式调用 RACSequence 这个类型的属性就可以了;例如 :下面方法可以遍历数组,当打印线程的时候在子线程中,不能在当前线程刷新UI

数组的遍历方式,有两种方式

下面是方法1,也是我们常用的

```

[arrays.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

    //不能更新UI

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"订阅信号");

}];

```

下面是方法二:RAC中精简版的

//映射,value就是集合;返回值:需要映射成那个值

```

    arrM = [[arrays.rac_sequence map:^id _Nullable(id  _Nullable value) {

        

        return [FlagItem itemWithDict:value];

    }] array];

    //arrM 是用来装模型的数组,里面有我们想要的转换的模型,arrays是一个json串

```

====================数组======================

字典的遍历

```

NSDictionary *dict = @{

                           @"name":@"wagner",

                           @"money":@123456

                           };

    

    //x 代表一个元组,在这里元组可以当做是数组来使用

    //RACTupleUnpack 把元组解析成通用的值类型

    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

        RACTupleUnpack(NSString *key, id value) = x;

        NSLog(@"%@ === %@",key,value);

    }];

* 输出打印:

```

2018-02-06 09:59:45.931174<0800 RACtest[2076:105197] name===wagner

2018-02-06 09:59:45.932966>0800 RACtest[2076:105197] money===123456

```

* ==================

* 关于 RACMulticastConnection的讲解

```

//    RACMulticastConnection :(RACSignal) 用于一个信号的订阅,被订阅多次,为了防止多次调用创建信号中的block,造成负面影响可以使用这个类做处理

    @weakify(self);

    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        

        @strongify(self);

        //网络数据请求,完毕了传递过去,loadData就是一个简单的网络请求函数

        [self loadData:^(id data) {

            [subscriber sendNext:data];

        }];

        

        return [RACDisposable disposableWithBlock:^{

            

        }];

    }];

    

#pragma mark - 多次订阅怎么办

    [signal subscribeNext:^(id  _Nullable x) {

        //接收数据刷新页面

    }];

    

    [signal subscribeNext:^(id  _Nullable x) {

        //接收数据刷新页面

    }];

```

* 解决以上方案的办法,订阅多次进行多次网络请求

```

//    RACMulticastConnection :(RACSignal) 用于一个信号的订阅,被订阅多次,为了防止多次调用创建信号中的block,造成负面影响可以使用这个类做处理

    @weakify(self);

    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        NSLog(@"网络数据发送请求");

        @strongify(self);

        //网络数据请求,完毕了传递过去,loadData就是一个简单的网络请求函数

        [self loadData:^(id data) {

            [subscriber sendNext:data];

        }];

        

        return [RACDisposable disposableWithBlock:^{

            

        }];

    }];

    //把信号转为 RACMulticastConnection 形式了

    RACMulticastConnection *cnt = [signal publish];

    //下来订阅的方法

    [cnt.signal subscribeNext:^(id  _Nullable x) {

        

    }];

    

    [cnt.signal subscribeNext:^(id  _Nullable x) {

        

    }];

    [cnt connect];

```

* RACMulticastConnection 的原理:RACSignal 创建信号的时候用 RACDynamicSignal 保存了block ;这个类其实和RACSubject类的使用差不多是一样的。

* 理解和思想说明:我觉得学到这里,个人感觉RAC的这三个类的作用的本质就是保存block,在适当的地方执行block,RACSubject 、 RACSignal 、RACMulticastConnection 三个类互相和做完成数据流的互换,看你想用那种形式的数据流的选择,然后在其中选择两个类互相使用就可以完美解决问题,这是我这段时间学习RAC这三个类的见解,有什么不对的地方还望大家伙见谅和提出。

 

=================RACCommand==============

* 关于 RACCommand 的讲解 : RAC用于处理事件的类

```

RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {

        //command 的block

        NSLog(@"%@",input);

        NSLog(@"====1");

        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

            //RACSignal 的 block

            NSLog(@"====2");

            [subscriber sendNext:@"hello"];

            [subscriber sendCompleted];

            return [RACDisposable disposableWithBlock:^{

                //RACDisposable 的 block

                NSLog(@"====end");

            }];

        }];

    }];

    

    //只要执行 execute 就会执行上面的 command 的 block

    //[command execute:@1] 这里会返回一个信号就是上面的 RACCommand 里面返回的那个 block

    [[command execute:@1] subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

输出结果:

```

2018-02-06 11:27:53.451167<0800 RACtest[2441:151535] 1

2018-02-06 11:27:53.451340>0800 RACtest[2441:151535] ====1

2018-02-06 11:27:53.457199<0800 RACtest[2441:151535] ====2

2018-02-06 11:27:53.457458>0800 RACtest[2441:151535] hello

2018-02-06 11:27:53.457807+0800 RACtest[2441:151535] ====end

```

RACCommand 中的 executionSignals 的block返回的还是信号,executionSignals 的 switchToLatest 表示最近一次发送的信号;executing 监听命令有没有完成,可以在 executing 监听的block中获取,executing有一个 skip 方法可以跳过第一次(一般时候我们跳过第一次),最后一次当我们使用完订阅者后必须发送一个 [subscriber sendCompleted] 。

下面是一个使用 RACCommand 的例子,判断状态的

```

RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {

        //command 的block

        NSLog(@"%@",input);

        NSLog(@"====1");

        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

            //RACSignal 的 block

            NSLog(@"====2");

            [subscriber sendNext:@"hello"];

            [subscriber sendCompleted];

            return [RACDisposable disposableWithBlock:^{

                //RACDisposable 的 block

                NSLog(@"====end");

            }];

        }];

    }];

    

    [[command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {

        if ([x boolValue]) {

            NSLog(@"正在执行");

        }else{

            NSLog(@"执行完毕");

        }

    }];

    

    [command execute:@1];

```

输出结果:

```

2018-02-06 14:10:55.555576<0800 RACtest[2733:176933] 1

2018-02-06 14:10:55.555752>0800 RACtest[2733:176933] ====1

2018-02-06 14:10:55.561215<0800 RACtest[2733:176933] 正在执行

2018-02-06 14:10:55.561410>0800 RACtest[2733:176933] ====2

2018-02-06 14:10:55.562035<0800 RACtest[2733:176933] ====end

2018-02-06 14:10:55.562554>0800 RACtest[2733:176933] 执行完毕

```

下面是 RACCommand 按钮的使用

按钮的 RAC 使用的方法1 

```

_loginBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {

        //command 的 block

        NSLog(@"按钮的点击");

        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

            //信号的 block ,没有涉及传递的话一般时候没啥作用

            [subscriber sendNext:input];

            

            return nil;

        }];

        

    }];

 

    [_loginBtn.rac_command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {

        NSLog(@"点击后要发送的值");

    }];

```

按钮的 RAC 使用的方法2-----当想用状态控制按钮的状态的时候一般用下面的方法

//这个用于控制按钮的状态

  RACSubject *subjectEnable = [RACSubject subject];

    

```

    _loginBtn.rac_command = [[RACCommand alloc] initWithEnabled:subjectEnable  signalBlock:^RACSignal * _Nonnull(id  _Nullable input) {

        

        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

            

            [subscriber sendNext:input];

            

            //请求数据核对完毕后调用

            [subscriber sendCompleted];

            return nil;

        }];

    }];

    

    //每次监听按钮的状态

    [[_loginBtn.rac_command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {

        [subjectEnable sendNext:@(![x boolValue])];

    }];

    

    [_loginBtn.rac_command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {

        NSLog(@"点击后要发送的值");

    }];

```

上面如果想让按钮点击一次之后不能再次点击最简单的做法是修改[subjectEnable sendNext:@(NO)]; 就可以了

 

=====================RAC 处理事件======================

下面是一个判断相应方法的例子:

```

+(instancetype)allocWithZone:(struct _NSZone *)zone

{

    ViewController *vc = [super allocWithZone:zone];

    [[vc rac_signalForSelector:@selector(viewDidLoad)] subscribeNext:^(RACTuple * _Nullable x) {

        NSLog(@"viewDidLoad");

    }];

    

    [[vc rac_signalForSelector:@selector(viewWillAppear:)] subscribeNext:^(RACTuple * _Nullable x) {

        NSLog(@"viewWillAppear");

    }];

    

    return vc;

}

```

关于 RAC 中KVO的使用,其中 keypath 是一个宏,在使用的时候前面记得加@ ,移除的话用OC的移除方法就可以了

方法1

```

[[self rac_valuesForKeyPath:@keypath(self,age) observer:self] subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

```

方法2,简洁的写法

```

[RACObserve(self, age) subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

```

关于按钮的点击事件的监听方法

//RAC 监听,subscribeNext 订阅信号

```

    [[_loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {

        NSLog(@"%@",x);

    }];

```

关于RAC 实现通知

```

NSString *notificationName = @"note";

    //监听通知,观察者不需要去管理,RAC 内部管理你的通知,你可以管理也可以不用管理

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:notificationName object:nil] subscribeNext:^(NSNotification * _Nullable x) {

        NSLog(@"监听到了通知");

    }];

    [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil];

```

RAC 事件绑定

方法1,输入框变化,lable的文字也会变化

```

[_testField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {

        NSLog(@"%@",x);

        _lable.text = x;

    }];

```

2

```

RAC(_lable,text) = _testField.rac_textSignal;

```

当一个页面发送多个请求的时候

//创建一个请求最热数据的信号

```

    RACSignal *hotSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        [subscriber sendNext:@"最热"];

        return [RACDisposable disposableWithBlock:^{

        }];

    }];

    

    RACSignal *newSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        [subscriber sendNext:@"最新"];

        return [RACDisposable disposableWithBlock:^{

            

        }];

    }];

    

    //Selector 当数组中的信号都发送一次 next 的时候就会调用 Selector 方法

    //使用的时候, Selector 要求有几个信号就有几个参数

    [self rac_liftSelector:@selector(updateUIHotData:newData:) withSignalsFromArray:@[hotSignal,newSignal]];

```

RAC + MVVM

/*框架思想:把业务划分清楚,使得代码更加的好维护;本质就是抽离不同层次的代码

MVC:

MVC S(业务类)

MVVM :2015

VIPER :2014(美团)

V:view

I:交互

P:展示

E:model

R:路由,也就是跳转,在iOS中也就是(push present)

*/

 

=====================RAC的hook======================

hook截获API的思想

ReactiveCocoa的操作核心 bind :绑定特点的属性,然后在block里面用 RACReturnSignal 返回修改的结果即可。

```

//需求:每次只要文本框的改变  + HWW ,函数式编程思想

    [[_textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{

        //信号改变就一会调用,并且把值传递过来

        NSLog(@"bind");

        return ^RACSignal *(id value, BOOL *stop){

            NSLog(@"旧值==%@",value);

            NSString *result = [NSString stringWithFormat:@"%@HWW",value];

            return [RACRet urnSignal return:result];

        };

    }] subscribeNext:^(id  _Nullable x) {

        NSLog(@"传递过来的新值:%@",x);

    }];

```

关于flatterMap的用法

Map是值的变化,flattenMap 是信号的变化

```

//对原数据的处理

    [[_textField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {

 

        value = [value stringByAppendingString:@"hhee"];

        return [RACReturnSignal return:value];

    }] subscribeNext:^(id  _Nullable x) {

        NSLog(@"===%@",x);

    }];

    

    // map方法

    [[_textField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {

        return [value stringByAppendingString:@"你好"];

    }] subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }] ;

```

上面的代码可以看出Map和 flattenMap的区别,两个的区别在于一个返回的是 string类型,二另外一个是 RACReturnSignal类型。

下面是信号中的信号的例子:

```

RACSubject *signalOfSingal = [RACSubject subject];

    RACSubject *signal = [RACSubject subject];

    [signalOfSingal subscribeNext:^(id  _Nullable x) {

        [x subscribeNext:^(id  _Nullable x) {

            NSLog(@"%@",x);

        }];

    }];

    [signalOfSingal sendNext:signal];

    [signal sendNext:@1];

```

使用flatten后关于信号中的信号的例子,和上一个例子一样

```

RACSubject *signalOfSingal = [RACSubject subject];

    RACSubject *signal = [RACSubject subject];

    [[signalOfSingal flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {

        return value;

    }] subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

    [signalOfSingal sendNext:signal];

    [signal sendNext:@1];

```

关于concat的用法,按照顺序执行的话用这个函数方法,但是注意的一点是,前一个信号sendCompleted 后,后面一个信号才可以执行。

场景:有可能两个信号当订阅的时候,需要用两次订阅,下面的这种形式,输出的答案但我们想要A和B的顺序,下面这种方案是实现不了的

```

RACSubject *signalA = [RACSubject subject];

    RACSubject *signalB = [RACReplaySubject subject];

    NSMutableArray *arrayM = [NSMutableArray array];

    //RACSubject 先订阅再发送,不想有顺序可以用RACReplaySubject

    [signalA subscribeNext:^(id  _Nullable x) {

        [arrayM addObject:x];

    }];

    [signalB subscribeNext:^(id  _Nullable x) {

        [arrayM addObject:x];

    }];

    [signalB sendNext:@"B"];

    [signalA sendNext:@"A"];

    //打印数组的值

    NSLog(@"%@",arrayM);

```

输出是:

```

(

    B,

    A

)

```

 

方法2,解决上面的问题

```

RACSubject *signalA = [RACSubject subject];

    RACSubject *signalB = [RACReplaySubject subject];

    NSMutableArray *arrayM = [NSMutableArray array];

    [[signalA concat:signalB] subscribeNext:^(id  _Nullable x) {

        [arrayM addObject:x];

    }];

    

    //发送信号

    [signalB sendNext:@"B"];

    [signalA sendNext:@"A"];

    [signalA sendCompleted];

    

    //打印数组的值

    NSLog(@"%@",arrayM);

```

输出的结果:

```

(

    A,

    B

)

```

then的用法

then和concat的区别,then一般用于当网络请求的时候,第一次网络请求完毕,再请求别的数据,例如类别和详情数据的展示

```

//解决请求网络类别,然后在请求其他详情的数据嵌套问题。这个方法在另外一个方法重调用

    [[[self loadCategoryData] then:^RACSignal * _Nonnull{

        return [self loadDetailData];

    }] subscribeNext:^(id  _Nullable x) {

        //显示详情数据

    }];

    

    // 下面两个方法是辅助作用

    //类别详情数据和类别的请求,只是写了函数,没写实现

    

-(RACSignal *)loadDetailData

{

    RACReplaySubject *subject = [RACReplaySubject subject];

    //发送网络请求

    [subject sendNext:@"detail"];

    return subject;

}

 

//分类数据

-(RACSignal *)loadCategoryData

{

    RACReplaySubject *subject = [RACReplaySubject subject];

    //发送网络请求

    [subject sendNext:@"category"];

    [subject sendCompleted];

    return subject;

}

```

注意点:关于网络数据请求用到多个信号处理数据的时候一般都用 RACReplaySubject 不用 RACSubject ,这个因为RACSubject 是必须先订阅后发送,而 RACReplaySubject则可以先发送后订阅和先后顺序没关系。

关于 merge,只要任何一个发送数据就能订阅,无序的,可以处理来自两个不同信号的请求数据,在同一个方法中进行统一的处理操作;concat 只有当定一个订阅者发送完毕后第二个才能订阅发送数据;then 第一个订阅者发送完毕,而且只能接收到最后一个订阅者发送的数据。

```

RACSubject *signalA = [RACSubject subject];

    RACSubject *signalB = [RACSubject subject];

    [[signalA merge:signalB] subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

    

    [signalB sendNext:@"B"];

    [signalA sendNext:@"A"];

```

关于zipWith,压缩同时要有数据,不然不会发送数据。结果是一个元组

```

//zipWith:合并

    RACSubject *signalA = [RACSubject subject];

    RACSubject *signalB = [RACSubject subject];

    [[signalA zipWith:signalB] subscribeNext:^(id  _Nullable x) {

        

        RACTupleUnpack(NSString *a,NSString *b) = x;

        NSLog(@"%@=%@",a,b);

    }];

    

    [signalB sendNext:@"B"];

    [signalA sendNext:@"A"];

```

posted on 2018-02-10 17:25  HWWY  阅读(168)  评论(0编辑  收藏  举报