RAC(ReactiveCocoa)介绍(一)——基本介绍
最近接触学习到了RAC(ReactiveCocoa),RAC是函数式+响应式编程结合,首先得去理解何为响应式函数编程(FRP)。
看了许多介绍,举一个最通俗易懂的例子——在命令式编程环境中, a = b+c表示将表达式的结果赋给 a,而之后改变 b 或 c的值不会影响 a。但在响应式编程中,a的值会随着 b或 c的更新而更新,意味着声明了一种绑定关系,b、c的变化会直接影响到a。
之前在iOS工作中,类之间的传值,无非就是block、delegate代理、KVO、notification这几种方法。在RAC中,同样具备替代KVO、delegate代理、通知、UI target、计时器timer、数据结构等各种方法。依据响应式函数编程,RAC方法本身更加简洁明了,通过提供信号的方式(RACSignal)可以捕捉当前以及未来的属性值变化,而且无需持续观察和更新代码。可直接在block中将逻辑代码加入其中,使得代码紧凑,更加直观。
先来介绍ObjC版本,使用cocoaPods在podfile中添加 pod 'ReactiveObjC', '~> 3.1.0' ,然后pod install一下。在项目中#import <ReactiveObjC.h>,建议放入pch头文件中。
通过RAC提供的方法与系统提供的方法分别进行对比,先来感受下RAC的强大之处。
1. UIButton


在RAC的block代码块中,打印x的属性为当前self.testButton的相关信息。

2. KVO
KVO在使用时,必须在- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context中实现针对KVO监听属性值变化的处理,而且对于KeyPath书写容易产生手写错误。在对应类dealloc时,KVO还必须要进行remove操作,否则会程序crash

在使用RAC代替KVO时,不仅能大大增加代码可读性,而且RACObserve(<#TARGET#>, <#KEYPATH#>)宏定义中keyPath可以代码提示出target中的属性成员变量,降低手写代码错误的可能性。

3. delegate代理
以UITextField为例,当需要对UITextField逻辑处理时,往往需要实现其各类代理方法,大大增加了代码量。当使用RAC之后

@selector方法选择器中键入要实现的代理方法,代理名称声明为对应的代理名称。block代码块中,当触发监听的代理方法时返回元组类型数据,与swift中的元组类型有所区别,此处的元组看起来更像是数组。

4. Notification通知


5. 定时器timer

6. 数组与字典
遍历元素


RAC基本使用方法与流程

以上代码中,subscribeNext作用为订阅信号,可在该block中输入逻辑相关代码块。但当多个对象的逻辑存在于block中需要修改时,仅仅subscribeNext已不能满足需求。
RAC中信号的其它动作:
信号映射:map、flattenMap
信号过滤:filter、ignore、distinctUntilChanged
信号合并:combineLatest、reduce、merge、zipWith
信号连接:concat、then
信号操作时间:timeout、interval、dely
信号跳过:skip
信号取值:take、takeLast、takeUntil
信号发送顺序:donext、cocompleted
获取信号中的信号:switchToLatest
信号错误重试:retry
在实际开发过程中,需要在RAC代码块中添加逻辑代码,避免不了引用当前类中的成员变量,那么需要在RAC方法外部写入以下代码:
@weakify(self)
在RAC的block代码块内部写入:
@strongify(self)

以此来避免出现block的循环引用,至于为何要如此声明,稍后会在后续文章中一一说明。
稍后会在后续的文章里继续介绍如何使用,以及RAC信号流程原理。demo代码放到GitHub上demo链接