iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好

内容来自stack overflow的一个回答:ReactiveCocoa vs RxSwift - pros and cons?

要直接比较这两个有点难。Rx 是 Reactive Extensions 的一部分,其他语言像C#, Java 和 JS 也有。Reactive Cocoa 受 Functional Reactive Programming(FRP) 启发,但是在最近一段时间里,他们提到也受到Reactive Extensions的启发。最终结果就是一个从Rx借鉴了一些东西,但是有着源自FRP名声的一个框架。

第一点要说明的事是无论是RAC还是Rx都不是真正意义上的Functional Reactive Programming。按照 What is (functional) reactive programming 里的回答对于FRP概念的定义。有了这个认识,我们就可以从两个框架如何处理subscribing/observing时的副作用(side effect)和一些其他的组件上两个方面来比较。

我们来看看社区(community)和技术实现(extra-tech)。

RAC是一个已经有着3年历史的项目,从Objective-C时期开始,后来从3.0开始支持了swift(可以通过bridge在OC下使用),接着就完全停止了在Objective-C上的维护。RxSwift项目的时间短一些只有几个月(作者写的时间是15年),但是社区似乎充满了动力。关于RxSwift有一件重要的事是项目是按照 ReactiveX这个组织的规定下开发的,并且所有其他语言的Rx项目也是一样。如果学会了如何使用RxSwift,再去学习Rx.Net, RxJava 或者 RxJS就是小菜一碟,只是语言语法上的差异。这真的就是learn once, apply everywhere.

再来看看技术实现。

Producing/Observing Entities

RAC 3.0主要有两个实体,<code>signal</code> 和 <code> SignalProducer </code>。第一个发布事件无论是否有绑定订阅者,后者要有一个信号或者事件产生才会触发。这两个区别是为了区分冷信号和热信号,也使很多开发者困惑。这就是他们处理副作用的一大区别。

在RxSwift,<code>signal</code> 和 <code> SignalProducer </code>变成了<code> Observable </code>,听起来有点困惑,但是这两个实体在Rx的世界里是同一个东西。在RxSwift里创建Observables不需要考虑是冷信号还是热信号,一旦你理解了他们的工作原理就很容易掌握。再次说明 冷/热(cold/hot/warm)信号就是当你subscribing/observing 产生的副作用。

对于订阅的概念两者基本是一样的。在RAC里有一点小的区别,RAC可以中断一个事件当信号被 <code> disposed </code>,即使在事件发送完成信号之前。总结一下两者都有的以下事件:

  • <code> Next </code>
    处理新收到的值
  • <code> Error </code>
    处理一个错误,结束整个流,对所有的观察者取消订阅
  • <code> Complete </code>
    标记整个流已经完成,取消所有观察者的订阅
    另外RAC会在收到一个disposed Signal后中断,即使没有收到complete或者error。

Manually Writing

在RAC中,Signal/SignalProducer都是只读的实体,他们不能从外部被改变,RxSwift中的Observable也是如此。如果要把Signal/SignalProducer改变成可以手动改写的实体,你只能通过调用<code>pipe()</code>函数返回一个可以改动的对象。在Rx中,这是一个不同的类型叫做<code>Subject</code>。
如果读/写这样的概念听起来不太明白,可以类比为未来/承诺(Future
/Promise)。未来只是一个只读的占位符(A Future is a read-only placeholder),就像Signal/SignalProducer和Observable。另外一方面,对于未来的承诺确可以手动自由的实现,就像pipe()和Subject。

Schedulers

这个部分两个框架都很类似,同样的概念。但是RAC是连续的,串行,Rx可以支持并发。

Composition

合成(Composition)是响应式编程的主要特点。合成成流都是两个框架的核心,在Rx中也称作sequences
在Rx中所有observable的实体的类型都是<code>ObservableType</code>,所以我们可以轻松的用同一个操作符将Subject和Observable的实例组合(compose)起来。
在RAC中,Signal和SignalProducer是两种不同的对象。我们必须把SignalProducer转换成Signal后才能compose由Signal实例产生的信号。这两个对象拥有各自的操作符。所以当你需要混合使用它们时,你必须考虑到某种操作符是否是两者通用,这个时候你也不必关心冷/热的处理了。

关于这个部分, Colin Eberhardt 很好的总结了:
现在signal的API主要关注在处理‘next’上,让你可以改变值,skip, delay, combine并且在不同的线程里观察值。signal producer的API主要处理信号的生命周期事件(completed, error),和一些这样的操作:then, flatMap, takeUntil 和catch。

其他

在RAC中还有<code>Action</code>和<code> Property </code>的概念。前者是一种处理副作用的类型,主要和用户交互相关。后者用于观察当执行了一个任务后值改变了的情况。在Rx中<code>Action</code>也会转变(translate)成一个<code> Observable </code>类型。这在RxCocoa中有很好的体现,一个集成了Rx基本元素后用于iOS和Mac平台。RAC中的<code> Property </code>可以对应于Rx中的<code> Variable </code>或者<code> BehaviourSubject </code>。
明白<code> Property </code>/<code> Variable </code>是我们连接必然世界和声明本质的响应式编程的的桥梁(bridge the imperative world to the declarative nature of Reactive Programming),所以当我们处理一些第三方库或者iOS/Mac中的核心功能(functionalities)时,<code> Property </code>/<code> Variable </code>有时是基础。

结论

RAC和Rx可以说是两种完全不同的物种,前者在Cocoa里有着长的历史和大量的参与者,后者很年轻,但是依靠着已经在其他语言里像java、js或者C#被验证过的有效理念。关于选谁比较好还是要考虑到自己的情况。RAC认为把观察的对象区分为热/冷是非常有必要的,并且这也是他们框架的一个核心特点。Rx则认为把这个统一为一种对象更好。再次说明,这影响的只是怎么处理订阅后的副作用。
RAC 3.0 在为了区分观察时的热/冷状态还引入了意料之外的复杂度,比如中断的概念,区分两种对象间不同的操作,引入一些必要行为(imperative behaviour)比如<code>start</code>是开始产生信号。对于一些人来说,这些东西很好甚至是一个杀手级功能,对于另外一些人而言会觉得这个并没有必要甚至有些危险。另外需要记住的一点是RAC一直努力和Cocoa的惯例尽量保持一致,如果你是一个资深的Cocoa开发者,你在使用RAC应该会觉得比Rx更顺手。
Rx中所有的对象都是observables。好的一件事是,是Reactive Extensions中的一员。从RxJS, RxJava 或者 Rx.Net中迁移过来是一件非常简单的事,所有概念都是一样的。这也让解决问题时会很有趣,因为你现在面临的问题,可能在RxJava中已经有人写过解决方案,你可以直接拿过来按照当前平台实现就可以。
这两个应该选哪一个关键看使用习惯,从一个客观的角度来说无法分辨出谁更好。最好的方式是打开Xcode,都试着使用这两个框架,看看那个用起来比较顺手。他们都是相同编程理念的实现,尝试达到同一个目的:使开发软件变得简单(simplifying software development)。

欢迎关注我的微博:@没故事的卓同学

相关链接:
函数式反应型编程(FRP) —— 实时互动应用开发的新思路
C语言里的side effect是什么意思?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容