- 1.ReactiveCocoa常见操作方法介绍
- 1.1 ReactiveCocoa操作须知
所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中,而RACSignal继承RACStream。
- 1.2. ReactiveCocoa操作思想
- 运用的是Hook(钩子)思想,Hook是一种用于改变API(应用程序编程接口:方法)执行结果的技术. - Hook用处:截获API调用的技术。 - Hook原理:在每次调用一个API返回结果之前,先执行你自己的方法,改变结果的输出。 - RAC开发方式:RAC中核心开发方式,也是**绑定**,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。 - 列如:把数据展示到控件上,之前都是重写控件的setModel方法,用RAC就可以在一开始创建控件的时候,就绑定好数据。
- 1.3 ReactiveCocoa核心方法bind
- 1.3.1.ReactiveCocoa操作的核心方法是bind(绑定),给RAC中的信号进行绑定,只要信号一发送数据,就能监听到,从而把发送数据改成自己想要的数据。
- 1.3.2.在开发中很少使用bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其他方法,底层都是调用bind,用法比bind简单.
- 1.3.3.bind方法简单介绍和使用。
- bind方法简单介绍和使用
假设想监听文本框的内容,并且在每次输出结果的时候,都在文本框的内容拼接一段文字“输出:”
方式一:在返回结果后,拼接。
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"输出:%@",x); }];
- 方式二:在返回结果前,拼接,使用RAC中bind方法做处理。
bind方法参数:需要传入一个返回值是RACStreamBindBlock的block参数 RACStreamBindBlock是一个block的类型,返回值是信号,参数(value,stop),因此参数的block返回值也是一个block。 RACStreamBindBlock: 参数一(value):表示接收到信号的原始值,还没做处理 参数二(*stop):用来控制绑定Block,如果*stop = yes,那么就会结束绑定。 返回值:信号,做好处理,在通过这个信号返回出去,一般使用RACReturnSignal,需要手动导入头文件RACReturnSignal.h。
- bind方法使用步骤:
- 1.传入一个返回值RACStreamBindBlock的block。
- 2.描述一个RACStreamBindBlock类型的bindBlock作为block的返回值。
- 3.描述一个返回结果的信号,作为bindBlock的返回值。
注意:在bindBlock中做信号结果的处理。
- 底层实现:
- 1.源信号调用bind,会重新创建一个绑定信号。
- 2.当绑定信号被订阅,就会调用绑定信号中的didSubscribe,生成一个bindingBlock。
- 3.当源信号有内容发出,就会把内容传递到bindingBlock处理,调用bindingBlock(value,stop)
- 4.调用bindingBlock(value,stop),会返回一个内容处理完成的信号(RACReturnSignal)。
- 5.订阅RACReturnSignal,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
- 注意:不同订阅者,保存不同的nextBlock,看源码的时候,一定要看清楚订阅者是哪个。
这里需要手动导入#import <ReactiveCocoa/RACReturnSignal.h>
,才能使用RACReturnSignal
。
[[_textField.rac_textSignal bind:^RACStreamBindBlock{ // 什么时候调用: // block作用:表示绑定了一个信号. return ^RACStream *(id value, BOOL *stop){ // 什么时候调用block:当信号有新的值发出,就会来到这个block。 // block作用:做返回值的处理 // 做好处理,通过信号返回出去. return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]]; }; }] subscribeNext:^(id x) { NSLog(@"%@",x); }];
- 1.4ReactiveCocoa操作方法之映射(flattenMap,Map)flattenMap,Map用于把源信号内容映射成新的内容。
- 1.4.1. flattenMap 用于信号中的信号,把源信号的内容映射成一个新的信号,信号可以是任意类型
flattenMap使用步骤:
1.传入一个block,block类型是返回值RACStream,参数value
2.参数value就是源信号的内容,拿到源信号的内容做处理
3.包装成RACReturnSignal信号,返回出去。
flattenMap底层实现:
0.flattenMap内部调用bind方法实现的,flattenMap中block的返回值,会作为bind中bindBlock的返回值。
1.当订阅绑定信号,就会生成bindBlock。
2.当源信号发送内容,就会调用bindBlock(value, *stop)
3.调用bindBlock,内部就会调用flattenMap的block,flattenMap的block作用:就是把处理好的数据包装成信号。
4.返回的信号最终会作为bindBlock中的返回信号,当做bindBlock的返回信号。
5.订阅bindBlock的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
代码:
//1.创建信号 RACSubject *subject =[RACSubject subject]; //2.绑定信号 [[subject flattenMap:^RACStream *(id value) { // block 只要原信号发送内容就会调用 // value 就是源信号发送的内容 NSLog(@"11---%@",[NSThread currentThread]); value = [NSString stringWithFormat:@"JK %@",value]; // 返回信号用来包装成修改内容的值 return [RACReturnSignal return:value]; }] subscribeNext:^(id x) { //3.订阅信号,flattenMap中返回的是什么信号,订阅的就是什么信号 NSLog(@"%@",x); NSLog(@"22---%@",[NSThread currentThread]); }]; //4.源信号发送信号 [subject sendNext:@"123"];
1.4.2.map简单使用
Map作用:把源信号的值映射成一个新的值
map使用步骤:
- 1.传入一个block,类型是返回对象,参数是value
- 2.value就是源信号的内容,直接拿到源信号的内容做处理
- 3.把处理好的内容,直接返回就好了,不用包装成信号,返回的值,就是映射的值。
Map底层实现:
- 0.Map底层其实是调用flatternMap,Map中block中的返回的值会作为flatternMap中block中的值。
- 1.当订阅绑定信号,就会生成bindBlock。
- 2.当源信号发送内容,就会调用bindBlock(value, *stop)
- 3.调用bindBlock,内部就会调用flattenMap的block
- 4.flattenMap的block内部会调用Map中的block,把Map中的block返回的内容包装成返回的信号。
- 5.返回的信号最终会作为bindBlock中的返回信号,当做bindBlock的返回信号。
- 6.订阅bindBlock的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
代码
//1.创建信号 RACSubject *subject =[RACSubject subject]; //2.绑定信号 [[subject map:^id(id value) { // 返回的内容就是你要映射的值 value = [NSString stringWithFormat:@"JK:%@",value]; return value; }]subscribeNext:^(id x) { NSLog(@"映射之后的值= %@",x); }]; //4.源信号发送信号 [subject sendNext:@"123"];
- 1.4.3.FlatternMap和Map的区别
- 1.FlatternMap中的Block返回信号。
- 2.Map中的Block返回对象。
- 3.开发中,如果信号发出的值不是信号,映射一般使用Map
- 4.开发中,如果信号发出的值是信号,映射一般使用FlatternMap。
- 1.4.3.总结:signalOfsignals(信号中的信号)用FlatternMap**
// 创建信号中的信号 RACSubject *signalOfsignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; // 创建订阅者 [[signalOfsignals flattenMap:^RACStream *(id value) { // 当signalOfsignals的signals发出信号才会调用 return value; }] subscribeNext:^(id x) { // 只有signalOfsignals的signal发出信号才会调用,因为内部订阅了bindBlock中返回的信号,也就是flattenMap返回的信号。 // 也就是flattenMap返回的信号发出内容,才会调用。 NSLog(@"%@aaa",x); }]; // 信号的信号发送信号 [signalOfsignals sendNext:signal]; // 信号发送内容 [signal sendNext:@1];
1.4.4.信号中的信号创建订阅者的3种方式
// 1.创建信号中的信号 RACSubject *signalOfsignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; //2.创建订阅者的种方式 //第1种方式 [signalOfsignals.switchToLatest subscribeNext:^(id x) { NSLog(@"%@",x); }]; // 第2种方式 [signalOfsignals subscribeNext:^(RACSignal *x) { [x subscribeNext:^(id x) { NSLog(@"%@",x); }]; }]; // 第3种方式 [[signalOfsignals flattenMap:^RACStream *(id value) { // 当signalOfsignals的signals发出信号才会调用 return value; }] subscribeNext:^(id x) { // 只有signalOfsignals的signal发出信号才会调用,因为内部订阅了bindBlock中返回的信号,也就是flattenMap返回的信号。 // 也就是flattenMap返回的信号发出内容,才会调用。 //5.打印信号发送的内容(可以进行修改) NSLog(@"%@aaa",x); }]; // 3.信号的信号发送信号 [signalOfsignals sendNext:signal]; // 4.信号发送内容 [signal sendNext:@1];
- 1.5 ReactiveCocoa操作方法之组合
- 1.5.1.concat:按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }]; RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@2]; return nil; }]; // 把signalA拼接到signalB后,signalA发送完成,signalB才会被激活。 RACSignal *concatSignal = [signalA concat:signalB]; // 以后只需要面对拼接信号开发。 // 订阅拼接的信号,不需要单独订阅signalA,signalB // 内部会自动订阅。 // 注意:第一个信号必须发送完成,第二个信号才会被激活 [concatSignal subscribeNext:^(id x) { NSLog(@"%@",x); }];
- 注意:第一个信号必须发送完成
[subscriber sendCompleted]
;,第二个信号才会被激活,按顺序打印出来.(前后按顺序实现,打印)
concat底层实现:
- 1.当拼接信号被订阅,就会调用拼接信号的didSubscribe - 2.didSubscribe中,会先订阅第一个源信号(signalA) - 3.会执行第一个源信号(signalA)的didSubscribe - 4.第一个源信号(signalA)didSubscribe中发送值,就会调用第一个源信号(signalA)订阅者的nextBlock,通过拼接信号的订阅者把值发送出来. - 5.第一个源信号(signalA)didSubscribe中发送完成,就会调用第一个源信号(signalA)订阅者的completedBlock,订阅第二个源信号(signalB)这时候才激活(signalB)。 - 6.订阅第二个源信号(signalB),执行第二个源信号(signalB)的didSubscribe - 7.第二个源信号(signalA)didSubscribe中发送值,就会通过拼接信号的订阅者把值发送出来.
- 1.5.2.then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号
then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号
注意使用then,之前信号的值会被忽略掉.(忽略掉前面的,只打印后面的)
底层实现:
1、先过滤掉之前的信号发出的值。
2、使用concat连接then返回的信号。
then代码
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }] then:^RACSignal *{ return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@2]; return nil; }]; }] subscribeNext:^(id x) { // 只能接收到第二个信号的值,也就是then返回信号的值 NSLog(@"%@",x); }];