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

```

上一篇:python中input()与raw_input()的区别到底是啥?-----marsggbo原创作品为你解答


下一篇:PHP实现的Mysql读写分离