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

```

转载于:https://www.cnblogs.com/whey/p/8439238.html

ReactiveCocoa的学习内容相关推荐

  1. 【JavaScript总结】JavaScript发展与学习内容

    发展: 最初浏览器是为大学里浏览文档用,从地址栏输入文档地址,找到文档显示. 后来各种需求(购物网站,个人博客)出现,已有功能不能满足需求. 可人们依旧在努力满足这种需求,但实现后的效果很不尽人意. ...

  2. 待办事项优先级 开发_如何通过创建主题待办事项确定学习内容的优先级

    待办事项优先级 开发 by Dan Draper 通过丹·德雷珀(Dan Draper) 如何通过创建主题待办事项确定学习内容的优先级 (How to prioritize what you lear ...

  3. 【组队学习】十月组队学习内容详情!(第30期)

    第30期 Datawhale 组队学习活动马上就要开始啦! 本次组队学习的内容为: 吃瓜教程--西瓜书+南瓜书 李宏毅机器学习(含深度学习) 深入浅出Pytorch 时间序列分析 机器学习数学基础 树 ...

  4. 【组队学习】【25期】Datawhale组队学习内容介绍

    第25期 Datawhale 组队学习活动马上就要开始啦! 本次组队学习的内容为: web开发入门教程 数据挖掘实战(异常检测) 集成学习(下) 大家可以根据我们的开源内容进行自学,也可以加入我们的组 ...

  5. 【组队学习】【24期】Datawhale组队学习内容介绍

    第24期 Datawhale 组队学习活动马上就要开始啦! 本次组队学习的内容为: 零基础入门语音识别(食物声音识别) Docker教程 数据挖掘实践(智慧海洋) 集成学习(中) 河北邀请赛(二手车价 ...

  6. layui概述||layui的学习内容

    概述 下载地址   https://www.layui.com/ 下载文件说明 layui.all.js   包含了所有模块的js layui.js   框架  如果要使用必须使用 layui.use ...

  7. 从0开始接触html--第一天学习内容总结

    第一天 总结: h1-h6 p 段落 hr br 有序 ol li 无序 ul li 定义列表 dl dt dd 块级元素:独占一行,h1-h6 p hr div 行内元素:共占一行, em和i st ...

  8. Java技术依然备受追捧,主要学习内容有哪些?

    Java技术依然备受追捧,主要学习内容有哪些?Java 语言是一门随时代快速发展的计算机语言程序,其深刻展示了程序编写的精髓,加上其简明严谨的结构及简洁的语法编写为其将来的发展及维护提供了保障. 在众 ...

  9. bpmn2.0业务过程模型和符号_IT帮业务架构学习小组学习内容

    关于学习内容,担心大家学完的可能不多,所以考虑是先选择一小部分来学.但考虑到业务架构属于组织级学科,本身就要求体系全面,所以还是决定把全套内容放入到本期学习.下面我列举一下我们这8个月在业务架构自主学 ...

最新文章

  1. lex/flex 笔记
  2. 微服务如何解决分布式事务
  3. 如何实现android和服务器长连接呢?推送消息的原理
  4. 修改数据表部分字段方法封装-及-动态生成对象并动态添加属性
  5. 【HNOI2006】鬼谷子的钱袋
  6. php多条件循环语句,PHP 实用教程-条件语句与循环语句
  7. web项目怎么打包上线_如何打包发布Web Application应用程序
  8. DEV、SIT、UAT、PRD的意思
  9. Android 签名机制 v1、v2、v3
  10. refreshToken的作用讨论及几点疑惑
  11. mysql中怎样把字段名改为中文_mysql修改字段名-Mysql,修改
  12. 客运综合管理系统项目解析-安全检查(模块)-车辆安检情况查询
  13. Unicast与Multicast
  14. lyle的第一篇博客
  15. 后羿采集器怎么导出数据_数据采集教程_智能模式_如何设置自动导出_后羿采集器...
  16. PYNQ(ZYNQ)入门资料合集1
  17. 怎么用计算机打出错误,电脑连接打印机怎么一直显示错误怎么办
  18. 物理引擎的赛车撞人游戏(一) 画地图 -- graphics
  19. java中的for语句格式_Java中foreach循环语句的格式可以写成(        )。
  20. 两个人在一起的相处之道

热门文章

  1. C#解决MDI窗体闪屏的方法
  2. 初学者,你应当如何学习C++以及编程-转
  3. L1-021. 重要的话说三遍-PAT团体程序设计天梯赛GPLT
  4. python3 logging模块中文乱码_Python logging模块写入中文出现乱码
  5. Oracle 判断CLOB字段是否为null
  6. oracle查询:分组查询,取出每组中的第一条记录
  7. Unsupported major.minor version (jdk版本错误)解决方案办法
  8. JSON 字符串 与 java 对象的转换
  9. Hive四种数据导入方式介绍
  10. 【转】深入分析 Parquet 列式存储格式