转载:http://www.jianshu.com/p/53eec1a2ad93
1.ReactiveCocoa是什么?
ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。
关键词:ReactiveCocoa是Github开源的一个框架@H_301_10@
2.ReactiveCocoa有什么用?
在iOS开发过程中,经常会响应某些事件来处理某些业务逻辑,例如按钮的点击,上下拉刷新,网络请求,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback等。
其实这些事件,都可以通过RAC处理,ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把要处理的事情,和监听的事情的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中高聚合,低耦合@H_301_10@的思想。
关键词:在iOS日常开发过程中使用的一些处理事件的方法,RAC也能处理并且更方便@H_301_10@
3.已知的编程思想都有哪些?
- 面向过程
- 处理事情以过程为核心,一步一步的实现。
- 面向对象
- 万物皆对象
- 链式编程思想
- 响应式编程思想
- 不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。
- 函数式编程思想
- 函数响应式编程(FRP)
4.如何导入ReactiveCocoa框架?
- 这里使用CocoaPods来导入
- 创建一个新的工程演示下框架的导入
- 打开终端,进入工程文件的同级目录
- 新建一个profile文件,输入一下内容并保存
use_frameworks! pod 'ReactiveCocoa','~> 4.0.2-alpha-1'
- 在终端输入指令
pod install@H_301_10@完成安装
5.ReactiveCocoa常见类有哪些?
第1种: RACSignal 信号类
@H_404_97@操作步骤:
- 创建信号(冷信号)
- 订阅信号(热信号)
- 发送数据
// 1.创建信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // block什么时候调用:当信号被订阅的时候就会调用 // block作用:在这里面传递数据出去 // 3.发送数据 [subscriber sendNext:@1]; return nil; }]; // 2.订阅信号 // x:信号传递出来的数据 [signal subscribeNext:^(id x) { // block什么时候调用:当信号内部,发送数据的时候,就会调用,并且会把值传递给你 // block作用:在这个block中处理数据 NSLog(@"%@",x); }];
RACSignal:表示有数据传递的时候
RACDisposable:取消订阅信号
RACSubscriber:订阅者,发送数据/* 执行流程: 1.创建信号RACDynamicSignal * 1.1 把didSubscribe保存到RACDynamicSignal 2.订阅信号 * 2.1 创建订阅者,把nextBlock保存到订阅者里面去 * 2 就会调用信号的didSubscribe 3.执行didSubscribe * 3.1 拿到订阅者发送订阅者 * [subscriber sendNext:@1]内部就是拿到订阅者的nextBlock * 信号被订阅,就会执行创建信号时didSubscribe * 订阅者发送信号,就是调用nextBlock */
第2种: RACDisposable 取消订阅或者清理资源
@H_404_97@
创建信号 订阅信号 发送信号 // 只要订阅者一直在,表示需要一直订阅信号,信号不会自动被取消订阅 // 1.创建信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { _subscriber = subscriber; // 3.发送信号 [subscriber sendNext:@1]; return [RACDisposable disposableWithBlock:^{ // 当信号取消订阅的时候就会调用 NSLog(@"信号被取消订阅"); }]; }]; // 2.订阅信号 RACDisposable *disposable = [signal subscribeNext:^(id x) { NSLog(@"%@",x); }]; // 取消订阅(主动取消) [disposable dispose]; }
第3种:RACSubject 信号提供者
@H_404_97@
信号提供者:既可以充当信号,也可以充当订阅者,发送数据 一个信号允许被多次订阅@H_301_10@
创建信号 订阅信号 发送信号 // 1.创建信号 RACSubject *subject = [RACSubject subject]; // 2.订阅信号 [subject subscribeNext:^(id x) { @"订阅者一%@",x); }]; [subject subscribeNext:^(@"订阅者二%@",x); }]; // 3.发送信号 [subject sendNext:@1];
/* 执行流程: 1.创建信号 2.订阅信号 * 创建订阅者 * [self subscribe:o]订阅信号,仅仅是把订阅者保存起来. 3.发送信号 * 把所有的订阅者遍历出来,一个一个的调用它们nextBlock */
第4种: RACReplaySubject 重复提供信号类(RACSubject的子类)
@H_404_97@允许先发送信号,在订阅信号 重复信号提供者@H_301_10@
// 1.创建信号 RACReplaySubject *subject = [RACReplaySubject subject]; // 2.发送信号 [subject sendNext:@"123123"]; [subject "345"]; [subject "456456"]; // 1.把值保存到数组 // 2.遍历所有的订阅者,调用nextBlock // 3.订阅信号 [subject subscribeNext:^(id x) { NSLog(@"订阅者一%@",x); }]; // 1.遍历所有值,拿到订阅者去发送 [subject "订阅者二%@",x); }];
/* 执行流程: 1.创建信号 2.订阅信号 * 创建订阅者,保存nextBlock保存 * 遍历valuesReceived需要发送的所有值,拿到一个一个值,利用订阅者发送数据 3.发送信号 * 把发送的值,保存到数组 * 把所有的订阅者遍历出来,一个一个的调用它们nextBlock */第5种:RACMulticastConnection
@H_404_97@用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理@H_301_10@
简单使用
id<RACSubscriber> subscriber) { @"发送请求"); // 3.发送信号 [subscriber sendNext:@"网络数据"]; // 2.把信号转换成连接类 RACMulticastConnection *connect = [signal publish]; // 3.订阅连接类的信号,注意:一定是订阅连接类的信号,不再是源信号 [connect.signal subscribeNext:^(// 4.连接 [connect connect];
一个信号即使被订阅多次,也只是发送一次请求RACMulticastConnection:用于信号中请求数据,避免多次请求数据@H_301_10@
/* 执行流程 1.创建信号 * 创建RACDynamicSignal,并且把didSubscribe保存到 2.把信号转换成连接类 * 创建信号提供者RACSubject * [self multicast:subject]:设置原始信号的多点传播subject,本质就是把subject设置为原始信号的订阅者 * 创建RACMulticastConnection,把原始信号保存到_sourceSignal,把subject保存到_signal 3.保存订阅者 4.连接 [connect connect] * 订阅_sourceSignal,并且设置订阅者为subject 5.执行didSubscribe 6.[subject sendNext]遍历所有的订阅者发送信号 */
第6种:RACCommand 用于处理事件的类
@H_404_97@RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,它可以很方便的监控事件的执行过程@H_301_10@
- 使用场景: 监听按钮点击,网络请求
- RACCommand使用步骤:创建命令 -> 执行命令
- RACCommand使用注意点:内部不允许传入一个nil的信号
// 1.创建命令 RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { // signalBlock调用时刻:只要命令一执行就会调用 // signalBlock作用:处理事件 return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { @"didSubscribe"); // didSubscribe调用时刻:执行命令过程中,就会调用 // didSubscribe作用:传递数据 // subscriber -> [RACReplaySubject subject] // RACReplaySubject:把值保存起来,遍历所有的订阅者发送这个值 [subscriber sendNext:@1]; return nil; }]; }]; // 2.执行命令 RACReplaySubject *replaySubject = (RACReplaySubject *)[command execute:@"执行命令"]; // 3.获取命令中产生的数据,订阅信号 [replaySubject subscribeNext:^(// 1.创建订阅者,订阅信号 // 2.遍历所有值,拿到订阅者去发送
/* 执行流程: // 1.创建命令 * 把signalBlock保存到命令中 // 2.执行命令 * 调用命令signalBlock * 创建多点传播连接类,订阅源信号,并且设置源信号的订阅者为RACReplaySubject * 返回源信号的订阅者 */
switchToLatest用法
// 1.创建了一个信号中的信号,只能发送信号 RACSubject *signalOfSignals = [RACSubject subject]; // 创建信号,发送普通数据 RACSubject *signalA = [RACSubject subject]; RACSubject *signalB = [RACSubject subject]; // 2.通过订阅信号中信号,拿到signal发出值 // 获取信号中的信号发送最新信号 [signalOfSignals.switchToLatest // 3.发送信号 // 信号中的信号发送数据 [signalOfSignals sendNext:signalA]; [signalOfSignals sendNext:signalB]; // 信号发送数据 [signalB "发送普通数据"];
// 1.命令执行的时候调用 @"执行SignalBlock"); // 处理事情,网络请求 id<RACSubscriber> subscriber) { // 2.执行完SignalBlock,接着就会调用 @"执行didSubscribe"); // 传送数据,也只会来一次 [subscriber sendNext:@"请求到网络数据"]; // 一定要做事情,声明数据传递完成 // 当数据传递完成,命令就执行完成 [subscriber sendCompleted]; // 直接获取命令中新发出信号 // switchToLatest:只能用于signalOfSignals // 作用:就是拿到signalOfSignals发出的最新信号 [command.executionSignals.switchToLatest subscribeNext:^(// 订阅当前命令执行状态的信号,正在执行,没有执行 [command.executing subscribeNext:^(id x) { // x:YES 正在执行 // x:No 没有执行/执行完成 if ([x boolValue] == YES) { @"正在执行"); }else{ @"没有执行/执行完成"); } }]; // 2.执行命令 RACSignal *signal = [command execute:@1];
6.ReactiveCocoa常用集合类?
RACTuple 和RACSequence 的使用
@H_404_97@RACTuple: 元组类,类似NSArray,用来包装值.RACSequence: RAC中的集合类,用于代替NSArray,NSDictionary,可以使用它来快速遍历数组和字典@H_301_10@
简单使用
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"1",@1,22)">@3,22)">@5]]; NSString *str = tuple[0];
OC->RAC
NSArray *arr = @[@"123",@1,152)">3,152)">5]; // OC数组转换成RAC集合 RACSequence *sequence = arr.rac_sequence; // 把集合转换成signal RACSignal *signal = sequence.signal; // 订阅集合类的信号,只要订阅这个信号,就会遍历集合中所有元素 [signal subscribeNext:^(id x) { 宏的使用
NSDictionary*dict = @{@"name":@"xmg",152)">@"age":@18}; [dict.rac_sequence.signal subscribeNext:^(RACTuple *x) { // id value = x[1]; // id key = x[0]; // 宏的参数,存放需要生成的变量名 // 宏会自动生成参数里面的变量 RACTupleUnpack(id key,id value) = x; @"%@ : %@",key,value); }];字典转模型
方式一:// RAC:集合,相当于数组或者字典 // 这个类的创建必须要依赖于数组或者字典 // 解析plist NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath]; _flags = [NSMutableArray array]; [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) { Flag *flag = [Flag flagWithDict:x]; [_flags addObject:flag]; }];
方式二:
NSMutableArray array]; _flags = [[dictArr.rac_sequence map:^id(id value) { // value:就是原始信号发送的值,字典 // block返回值就是需要映射的对象 return [Flag flagWithDict:value]; }] array];