简言
最近要将项目从 MVC 到 MVVM 迁移做组件化开发,
经过查阅资料发现 ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把要处理的事情,和监听的事情的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中高聚合,低耦合的思想。
所以决定深入学习一下 RAC,本文章会持续更新并且上传相应的 Demo 供大家指正
RAC
ReactiveCocoa简称RAC,就是基于响应式编程思想的Objective-C实践,它是Github的一个开源项目
ReactiveCocoa框架概览
RAC几乎接管了Apple所有的事件机制,由于RAC将Cocoa中KVO、UIKit event、delegate、selector等都增加了RAC支持,所以都不用去做很多跨函数的事。
- leezzhong的博客中有这样的比喻,能让你对ReactiveCocoa的信号传递有个很好的理解:
可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。可以在水龙头上加一个过滤嘴(filter),不符合的不让通过,也可以加一个改动装置,把球改变成符合自己的需求(map)。也可以把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。
Streams
Streams 表现为RACStream类,可以看做是水管里面流动的一系列玻璃球,它们有顺序的依次通过,在第一个玻璃球没有到达之前,你没法获得第二个玻璃球。 RACStream描述的就是这种线性流动玻璃球的形态,比较抽象,它本身的使用意义并不很大,一般会以signals或者sequences等这些更高层次的表现形态代替。
Signals
Signals 表现为RACSignal类,就是前面提到水龙头,ReactiveCocoa的核心概念就是Signal,它一般表示未来要到达的值,想象玻璃球一个个从水龙头里出来,只有了接收方(subscriber)才能获取到这些玻璃球(value)。
Signal会发送下面三种事件给它的接受方(subscriber),想象成水龙头有个指示灯来汇报它的工作状态,接受方通过-subscribeNext:error:completed:对不同事件作出相应反应
- next 从水龙头里流出的新玻璃球(value)
- error 获取新的玻璃球发生了错误,一般要发送一个NSError对象,表明哪里错了
- completed 全部玻璃球已经顺利抵达,没有更多的玻璃球加入了
一个生命周期的Signal可以发送任意多个“next”事件,和一个“error”或者“completed”事件(当然“error”和“completed”只可能出现一种)
Subjects
subjects 表现为RACSubject类,可以认为是“可变的(mutable)”信号/自定义信号,它是嫁接非RAC代码到Signals世界的桥梁,很有用。嗯。。。 这样讲还是很抽象,举个例子吧:
RACSubject:信号提供者,自己可以充当信号,又能发送信号。使用场景:通常用来代替代理,有了它,就不必要定义代理了
RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters sendNext:@"a"];
可以看到@''a"只是一个NSString对象,要想在水管里顺利流动,就要借RACSubject的力。
RACReplaySubject
重复提供信号类,RACSubject的子类。
RACReplaySubject与RACSubject区别:RACReplaySubject可以先发送信号,再订阅信号,RACSubject就不可以。
- 使用场景一:如果一个信号每被订阅一次,就需要把之前的值重复发送一遍,使用重复提供信号类。
- 使用场景二:可以设置capacity数量来限制缓存的value的数量,即只缓充最新的几个值。
Commands
command 表现为RACCommand类,可以认为是回应某些动作的信号,同常触发该信号的动作都UI控件
Sequences
RAC中的集合类,用于代替NSArray,NSDictionary,可以使用它来快速遍历数组和字典。
sequence 表现为RACSequence类,可以简单看做是RAC世界的NSArray,RAC增加了-rac_sequence方法,可以使诸如NSArray这些集合类(collection classes)直接转换为RACSequence来使用。
Schedulers
scheduler 表现为RACScheduler类,类似于GCD
RACTuple
元组类,类似NSArray,用来包装值.
常用宏
- RAC 可以看作某个属性的值与一些信号的联动
RAC(<#TARGET, ...#>)
RAC(self.submitButton.enabled) = [RACSignal combineLatest:@[self.usernameField.rac_textSignal, self.passwordField.rac_textSignal]
reduce:^id(NSString *userName, NSString *password) {
return @(userName.length >= 6 && password.length >= 6);
}];
- RACObserve 监听属性的改变,使用block的KVO
RACObserve(<#TARGET#>, <#KEYPATH#>)宏则用来生成一个对象的绑定属性的信号量,
@property (nonatomic, strong) NSString* testText;
@property (nonatomic, strong) NSString* testText_2;
RAC(self,testText) = RACObserve(self, testText_2);
这个例子中,testText_2属性有任何变动,都会通知给testText变成一样的内容,
testText变化不会影响testText_2。RAC宏在等号左边,右边RACObserve宏返回一个传值信号量。
- UI Event
RAC为系统UI提供了很多category,非常棒,比如UITextView、UITextField文本框的改动rac_textSignal,UIButton的的按下rac_command等等。
常用的方法
ReactiveCocoa常见的方法:
1 代替代理: rac_signalForSelector:用于替代代理。
2 代替KVO : rac_valuesAndChangesForKeyPath:用于监听某个对象的属性改变。
3 监听事件: rac_signalForControlEvents:用于监听某个事件。
4 代替通知: rac_addObserverForName:用于监听某个通知。
5 监听文本框文字改变:rac_textSignal:只要文本框发出改变就会发出这个信号。
6 处理当界面有多次请求时,需要都获取到数据时,才能展示界面;rac_liftSelector:withSignalsFromArray:Signals:当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法。