ReactiveCocoa学习笔记(一):ReactiveCocoa的前世今生

最近很长一段时间在研究ReactiveCocoa这个框架,因此将会写一系列的文章来记录和总结一下学习过程中的心得体会。本文是这个系列的第一篇,主要介绍了ReactiveCocoa的诞生背景和发展,以及现在的版本情况。

就像公司招聘员工工作之前,都要从简历来了解员工前面的学习、工作经历一样。我们在深入了解ReactiveCocoa这个强有力的工具之前,也有必要来了解一下它的前世今生,这也有助于更好理解它的核心思想和工作方式。

从Reactive Extensions说起

C#3.0中引入了Language Integrated Query(LINQ)这种语言特性。LINQ是对.NET的一个扩展,提供了统一的语法来从不同数据源中查询和提取数据。它的函数性和声明式语法使得我们的处理逻辑变得简单清晰。

Reactive Extension(Rx)是对LINQ的一种扩展,起源于Microsoft DevLabs的研究。它主要提供了一种组织和协调异步事件的方式。如果说LINQ专注的是处理静态集合数据,那么Rx处理的就是异步获得的集合数据。LINQ面对的是“现在”的数据,则Rx是定义了如何去处理“未来”的数据(例如将从服务器返回的数据)的方式。

Rx的核心思想是两点:集成式的异步编程和事件驱动的编程。

  • 集成式的异步编程(composing asynchronous):Rx将各种异步的逻辑统一集成到同一处代码,而不是分散在代码各处进行处理。这样使得代码逻辑更加集中和清晰。
  • 基于事件(event-based):Rx处理的是(未来的)数据/事件的集合,并提供了一系列的操作工具来声明式地处理这些集合。

Rx使用一种可观察集合(Observable Sequence)来实现上述功能。可观察集合是Rx的核心,它是代表未来的值/事件的一个集合。我们声明了异步处理这些值的方式,这样当未来的值被添加到集合中的时候,我们便能够观察到(接收到)这些值并进行处理。

RxSwift和ReactiveCocoa

Rx是一个很大的家族,号称「ReactiveX is everywhere, and it’s meant for everything」。各大主流编程语言中都有它的身影,比如Java的RxJava,JavaScript的RxJS,C++的RxCpp等。从前端到后端,Rx家族都有很大的舞台。对于移动端iOS开发来说,也有这么一个大家族的成员——Swift的RxSwift

是的,RxSwift才是Rx家族的正统血统。那么,我们的主角ReactiveCocoa和它有什么关系呢?

并没有什么关系(手动滑稽)。

ReactiveCocoa是一个Cocoa的扩展框架,它是Justin Spahr-SummersJosh Abernathy在开发GitHub for Mac的过程中的副产物。ReactiveCocoa受Functional Reactive Programming(FRP)的启发,但是最近他们提到也受到过Rx的启发。因此,可以说ReactiveCocoa是借鉴了一些Rx的精神,源自于FRP的一个框架。这两者是同一编程思想的两种不同实现。

RxSwift和ReactiveCocoa是很神似的,它们都是函数式的、响应式的框架(但都不是真正意义上的函数响应式,后续文章会讲到)。但是又有一些不同点:

  • ReactiveCocoa是一个有4年历史的框架,经历了很多大型项目的实践运用
  • RxSwift时间短一点。但是社区非常有活力。另外,由于RxSwift是Rx的正统家族成员,因此,在RxSwift、RxJava、RxJs等框架间迁移十分方便,可以说是「Learn once, apply everywhere」

此外,两者还有一些技术实现上的差别,这主要体现在他们是如何处理「副作用」的。关于副作用(Side-Effect),在后续的博文中会详细介绍,这里只需要理解成在创建一个可观察集合(ReactiveCocoa中为信号),以及对其进行观察时对该集合外部代码产生的影响:

  • ReactiveCocoa中的核心概念是两种信号:SignalSignal Producer,分别称为「冷信号」和「热信号」。ReactiveCocoa用这种概念的区分来处理副作用。
  • RxSwift则只有一个核心概念:Observable。因此,在创建一个Observable时,要仔细考虑它应当是「冷信号」还是「热信号」。同样,这也是为了处理副作用。

另外,尽管RxSwift和ReactiveCocoa对事件的定义都是类似的,都有三种类型的事件:

  • Next:新产生的值
  • Error:发送一个错误值,并终止该可观察集合(信号),移除对它的观察者
  • Complete:发送一个代表「完成」的值,并终止该可观察集合(信号),移除对它的观察者

但是ReactiveCocoa中,当一个信号在正常结束前(发送一个Error或者Complete)就被销毁了,还会发送另外一种称为Interruption的值。

除此之外,尽管还有一些细小的差别,但是RxSwift和ReactiveCocoa的用法和原理基本都是类似的。

项目中该如何选择?

在挑选去使用其中一个的时候,可以想想对于上述两个框架对「冷信号」和「热信号」的差别处理,你更接受哪个。

此外,ReactiveCocoa一直在不断更新,以更适合开发者对Cocoa框架的使用习惯。因此,如果你对Cocoa框架的开发很有经验,应当会更容易上手ReactiveCocoa这个框架;相反,如果你之前熟悉Reactive Extension,例如RxJava,RxJs,Rx.Net等等,那么你会对RxSwift更加得心应手。

ReactiveCocoa的2.5.0版本及以下为Objective-C版本,3.0.0版本以上到最新的发布版本6.0.0为Swift版本,现在支持到Swift 3.0.x。此外,原来的ReactiveCocoa库现在被拆分成了四个库:

  • ReactiveCocoa:现如今的ReactiveCocoa库主要是作为UIKitAppKit的扩展,所做的更多是业务方面的工作。依赖于ReactiveSwift。
  • ReactiveSwift:ReactiveSwift是原来ReactiveCocoa库中拆分出来的只和Swift相关的核心库。这个库非常精简,且不依赖平台。ReactiveCocoa + ReactiveSwift可以用来完成CocoaCocoaTouch的开发, 而毕竟Swift已经是一门开源的语言,所以将ReactiveSwift分离出来以适用于其他平台的开发。
  • ReactiveObjC:这就是原来ReactiveCocoa库中Objective-C相关的部分。它和ReactiveSwift算是同胞兄弟的关系,一样的功能,两套API。
  • ReactiveObjcBridge:由于上述ReactiveObjc和ReactiveSwift的兄弟分家,于是就有了ReactiveObjcBridge这个桥接这两套API的库。它可用于一些老的项目从Objective-C向Swift转换,或是Objective-C和Swift混编的项目。

Reference

reactivex主页

reactivecocoa vs rxswift-pros and cons?

ReactiveCocoa v2.5 源码解析之架构总览

初探 ReactiveSwift