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"];
```
•
•
•
•
•
•
•
•