1.ReactiveCocoa简介
ReactiveCocoa(简称RAC),是由Github开源的一个应用于IOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。
2.ReactiveCocoa作用
在我们IOS开发中,经常会响应某些事件来处理某些业务逻辑,例如按钮的点击、上下拉刷新、网络请求、属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback等。
其实这些事件,都可以通过RAC处理,ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把处理的事件和监听的事件的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中高内聚、低耦合的思想。
3.编程思想
在开发中我们也不能太依赖于某个框架,否则这个框架不更新了,导致项目后期没办法维护,比如之前Facebook提供的Three20框架,在当时也是神器,但后来不更新了,也就没什么人用了。因此我感觉学习一个框架,还是有必要了解它的编程思想。
先简单地介绍下目前我们已知的编程思想:
3.1、面向过程:处理事物以过程为核心,一步一步地实现。
3.2、面向对象:万物皆对象。
3.3、链式编程思想:是将多个操作(多行代码)通过点语法链接在一起成为一句代码,是代码可读性好。
链式编程特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)。
代表:masonry框架
3.4、响应式编程思想:不用考虑调用顺序,只需考虑调用结果。类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。
代表:KVO运用
3.5、函数式编程思想:是把操作尽量写成一系列嵌套的函数或者方法调用。
函数式编程特点:每个方法必须有返回值(本身对象),把函数或者Block当做参数block(需要操作的值)block返回值(操作结果)
代表:ReactiveCocoa
4.ReactiveCocoa编程思想
ReactiveCocoa结合了几种编程风格:
函数式编程(Functional Programming)
响应式编程(Reactive Programming)
所以,你可能听说过ReactiveCocoa被描述为函数响应式(FRP)框架。
以后使用RAC解决问题,就不需要考虑调用顺序,直接考虑结果,把每一次操作都写成一系列嵌套的方法中,使代码高集合,方便管理。
5.如何导入ReactiveCocoa框架
从上图这样导入RAC框架会发现,会报错的。
解决办法:加上 'use_frameworks!'
6.ReactiveCocoa常见类
学习框架首要之处:个人认为先要搞清楚框架中常用的类,在RAC中最核心的类RACSignal,搞定这个类就能用ReactiveCocoa开发了。
RACSignal:信号类,一般表示将来有数据传递,只要有数据改变,信号内部接收到数据,就会马上发出数据。
信号类(RACSignal),只是表示数据改变时,信号内部会发出数据,它本身不具备发送信号的能力,而是交给内部一个订阅者去发出。
默认一个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发。
如何订阅信号:调用信号RACSignal的subscribeNext就能订阅。
6.1.RACSignal的简单运用:
RACSignal使用步骤:
1.创建信号:+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe
2.发送信号:- (void)sendNext:(id)value (这步不一定有)
3.订阅信号,才能激活信号:- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
RACSignal底层实现:
1.创建信号,首先把didSubscribe保存到信号中,还不会触发
2.当信号被订阅,也就是调用signal的subscribeNext:nextBlock
2.subscribeNext内部会创建订阅者subscriber,并把nextBlock保存到subscriber中
2.subscribeNext内部会调用signal的didSubscribe
3.signal的didSubscribe中调用[subscriber sendNext:@1];
3.1 sendNext底层其实就是执行了subscriber的nextBlock
我们来创建一个信号并发送
创建信号并发送我们运行程序可以发现,控制台并没有打印NSLog里的字符串,也印证了,创建的信号默认是个冷信号,需要我们手动去激活变成热信号,只有当信号被订阅了,才会调用。
这里,我加上了订阅信号方法后,可以看到,控制台正常输出了想要的东西。 (注:信号内部发送数据,订阅方法就被调用;信号被订阅,信号内部就会被调用)
RACSubscriber:表示订阅者的意思,用于发送信号,这是一个协议,不是一个类,只要遵循这个协议,并且实现方法才能成为订阅者。通过create创建的信号,都有一个订阅者,帮助它发送数据。
RACDisposable:用于取消订阅者或者清理资源,当信号发送完毕或者发送错误的时候,就会自动释放它。一般使用的地方:不想监听某个信号时,可以通过它来主动取消订阅者号。
1.需要在信号被订阅的时候,返回一个RACDisposable,才能取消信号。
2.只要订阅信号,就会返回一个取消信号的对象,通过subscribeNext订阅,返回来RACDisposable对象,再通过dispose来主动取消信号
6.2.RACSubject
信号提供者,自己可以充当信号,又能发送信号。rac中热信号的源头,继承于RACSignal
RACSubject的使用步骤:
1.创建信号 [RACSubject subject],跟RACSignal不一样,创建信号时没有block。
2.订阅信号- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
3.发送信号- (void)sendNext:(id)value
RACSubject底层实现和RACSignal不一样:
1.调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值。
2.调用sendNext发送信号,遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock
RACSubject的简单使用:
单个订阅 多个订阅看log可以看出racsubject和racsignal有本质的区别,不关心历史值,错过就错过了,当发出第二个信号时,第一个订阅者收到的数据会相对于发生更新,所以不用去考虑历史值。
6.3.RACReplaySubject
重复提供信号类,RACSubject的子类。
使用场景:
1.如果一个信号每被订阅一次,就需要把之前的值重新发送一遍,使用重复提供信号类。
2.可以设置capcity数量来限制缓存的value的数量,即只缓存最新的几个值
RACReplaySubject的简单使用:
只订阅1次 订阅2次可以看到log打印,把之前的值都重新发送了一遍。
6.4.RACTuple和RACSequence
RACTuple:元组类,类似NSArray,用来包装值
RACSequence:RAC中的集合类,用来代替NSArray、NSDictionary,可以使用它来快速遍历数组和字典。
使用场景:字典转模型
RACSequence和RACTuple的简单使用
主要有3个步骤 (numbers为数组)
1.把数组转化成集合RACSequence ->numbers.rac_sequence
2.把集合RACSequence转化成RACSignal信号类 ->numbers.rac_sequence.signal
3.订阅信号,激活信号,会自动把集合中的所有值遍历出来 ->subscribeNext
RACSequence从log打印可以看到,遍历字典,有个RACTuple对象。那么可以通过RACTuple来处理,方便接下来直接取出key-value
RACTuple1 RACTuple宏字典转模型
通过map(映射)将数组遍历的集合映射成一个新值(模型)
步骤:
1. map:映射的意思,目的:把原始值value映射成一个新值
2.toArray:把集合转成数组
底层实现:当信号被订阅,会遍历集合中的原始值,映射成新值,并保存到数组中
字典转模型6.5.RACCommand
RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,可以很方便的监控事件的执行过程。
使用场景:监听按钮点击,网络请求
使用步骤:
1.创建命令- (id)initWithSignalBlock:(RACSignal * (^)(InputType input))signalBlock;
2.在signalBlock中,创建RACSignal,并作为signalBlock的返回值。
3.执行命令- (RACSignal *)execute:(InputType)input;
注意事项:
1.signalBlock必须返回一个信号,不能传nil
2.如果不想传递信号,直接创建空的信号[RACSignal empty]
3.RACCommand中信号如果数据传递完,调用[subscriber sendCompeted]来保证发送信号完毕,不会有更多的信号发送。
4.RACCommand需要被强引用,否则接受不到RACCommand中的信号,因此RACCommand的信号是延迟发送的。
从上图,可以看出,创建命令返回的是一个信号RACSignal,我们也知道信号可以发信号,所以,就有executionSignals信号源的概念
executionSignals 信号源,包含事件处理的所有的信号
定义:信号中发信号,也就是信号发出的数据也是信号。
信号发送信号明白了信号发送信号的原理后,我们来看看executionSignals信号源如何去操作的。需要注意的是想要信号源接收到信号内容,需要将命令类强引用保持,保证命令类不被销毁。(在这里我就设置成全局)
RACCommand->RACSignals6.6.RACMulticastConnection
用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理。
使用注意:RACMulticastConnection通过RACSignal的-publish或者-muticast:方法创建
使用步骤:
1.创建信号+ (RACSignal *)createSignal:(RACDisposable * (^)(idsubscriber))didSubscribe;
2.创建连接RACMulticastConnection *connect = [signal publish];
3.订阅信号,注意:订阅的信号不是之前的信号,而是连接的信号[connection.signal subscribeNext:nextBlock]
4.连接 [connect connect];
底层原理:
1.创建connect,通过publish(multicast:)创建sourceSignal(指向原信号),connect.signal ->RACSubject
2.订阅connect,会调用RACSubject的subscribeNext,创建订阅者,并把订阅者保存起来,并不会去去执行,也就是说现在的connect.signal信号是冷信号。
3.[connect connect]内部会订阅RACSignal(原始信号),并且订阅者就是RACSubject,调用了此方法才能将信号变成热信号。
3.订阅原始信号,就会调用didSubscribe
3.didSubscribe后,拿到订阅者调用sendNext,其实就是调用RACSubjec的sendNext
4.sendNext后,就会遍历所有订阅者发送信号
使用场景:
如果一个信号发出请求,每次订阅一次都会发出请求,这样导致多次请求,就可以利用RACMulticastConnection来解决
简单使用:
单独的订阅信号如果不使用连接,可以发现,每次去订阅一次信号,就会去重复调NSLog(),这个也就是副作用。
加上连接Signal可以看到,就不会去重复请求了。
7.ReactiveCocoa开发中常见用法
1.代替代理:
ran_signalForSelector:用于代替代理
场景:在控制器设置一个view,view里放个按钮button,然后点击button,让控制器知道按钮被点了。
拓展:RACDelegateProxy 代理类
这个类通常用在多个对象,但各种在代理方法中处理的事件不同,或者说实现不同的需求(注:RACDelegateProxy可能会被无缘无故地crash,所以需要强引用保留住)
订阅信号返回block参数x就是当前操作的textField。这样写代理,符合了高内聚的思想,不必去到处找代理方法位置。
2.代替KVO:
rac_valuesAndChangesForKeyPath:用于监听某个对象的属性改变
场景:点击屏幕,年龄age++,来监听age变化值
3.监听事件:
rac_signalForControlEvents:用于监听某个事件
4.代替通知:
rac_addObserverForName:用于监听某个通知
场景:监听键盘弹出
5.监听文本框文字改变:
rac_textSignal:只要文本框发出改变就会发出这个信号
6.处理当界面有多次请求时,需要都获取到数据时,才能显示界面:
rac_liftSelector:withSignalsFromArray:Signals:当传入的Signals(信号数组),每一个signal(都至少sendNext过一次,就会去触发第一个selector参数的方法)。
场景:一个页面里,有2个不同的请求(分别是热门商品的请求和最新商品的请求),只有当2个请求都请求完毕后才更新界面。
我们将最新商品发送信号方法senNext注释掉,会发现就不会去调更新UI方法了。
8.ReactiveCocoa常见的宏
总结:
ReactiveCocoa框架是个重量级框架,学习起来确实比较费时间,学习一个框架,要去了解框架编程思想,比如Masonry框架,采取的是链式编程,ReactiveCocoa框架,采取的是函数响应式编程。框架固然方便了程序员,但不能太过于去依赖,如果有一天框架没更新了,写的代码就真的炸了,为此,我不推荐项目迭代时间较久的去使用第三方框架。
网友评论