ReactiveCocoa------ReactiveCocoa简介

简介

ReactiveCocoa是一个将函数响应式编程范例带入Objective-C的开源库。由Josh AbernathyJustin Spahr-Summers在对GitHub for Mac的开发过程中产生的副产物。RAC富含cocoa框架多种组件,提供基于时间变化的数据流的组合和变换。

函数响应式编程

函数响应式编程是思考软件将输入转化为输出在时间上的持续过程的一种方式。它糅合了函数式编程和响应式编程的特点,满足函数式编程的一些特性,将时间轴上的离散事件通过响应式编程的数据流向下传播的一种编程范式。

先来看一下什么是函数式编程/响应式编程。

函数式编程(FP)

函数式编程是一种编程范式,它将电脑运算视为数学上的函数计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。

在之前的一篇文章里对FP做了更详尽的剖析,这里就不多做解读。(强烈建议阅读继续阅读之前阅读该篇文章)。

响应式编程 (RP)

响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态数据流,而相关计算模型会自动将变化的值通过数据流进行传播。

举个栗子

命令式编程环境中
a = b + c
赋值之后b或c的值变化后,a的值不会跟着变化
而在响应式编程中,a的值会随着b或c的更新而更新。

Excel就是响应式编程的另一个例子。对数据进行求和或求均值操作,包含公式结果的单元格的值会根据其他单元格的值的变化而变化。
iOS开发中的Autolayout也是响应式编程的一个例子。当父View的位置发生变化,根据相互之间的关系Constraint,子View的frame也会随之变化。

为什么使用FRP

函数式响应编程提高了代码抽象层次,所以我们可以只关注定义了业务逻辑的那些相互依赖的事件,而非纠结于大量的实现细节。FRP的代码往往会更加简明。

特别是在开发现在这些有着大量与数据事件相关的 UI events 的高互动性 Webapps、手机 apps 的时候,FRP 的优势就更加明显。10年前,网页的交互就只是提交一个很长的表单到后端,而在前端只产生简单的渲染。Apps 就表现得更加的实时了:修改一个表单域就能自动地把修改后的值保存到后端,为一些内容”点赞”时,会实时的反应到其它在线用户那里等等。

现在的 Apps 有着大量各种各样的实时 Events,以给用户提供一个交互性较高的体验。我们需要工具去应对这个变化,而函数响应式编程就是一个答案。

举个栗子

示例引用于:响应式编程介绍

假设我们想要得到一个包含”双击”事件的Stream。为了使它更有趣,假设我们想要这个Stream要同时考虑三击,或更加宽泛,连击。想象一下在传统的命令式编程中应该怎样实现。我敢打赌代码会像一团乱麻,并且会使用一些变量保存状态,同时也有一些计算时间间隔的代码。

而在响应式编程中,这个功能的实现就非常简单。事实上,这逻辑只有四行代码。但现在我们不管这些代码。用图表的方式思考是理解怎样构建Stream的最好方法。

灰色的方框是用来转换 Stream 函数的。

  • 首先,简而言之,我们把连续 250 ms 内的 Click 都积累到一个列表中(就是 buffer(stream.throttle(250ms) 做的事),结果是一个列表的 Stream。
  • 然后我们使用 map() 把每个列表映射为一个整数,即它的长度。
  • 最终,我们使用 filter(x >= 2) 把整数 1 给过滤掉。就这样,3 个操作就生成了我们想要的 Stream。
  • 然后我们就可以订阅(“监听”)这个 Stream,并以我们所希望的方式作出反应。

我希望你能感受到这个示例的优美之处。这个示例只是冰山一角:你可以把同样的操作应用到不同种类的 Stream 上,例如,一个 API 响应的 Stream;另一方面,还有很多其它可用的函数。

基于时间变化的数据流

前面提到,RAC提供基于时间变化的数据流的组合和变化,那么什么是基于时间变化的数据流?

连续数据流 & 离散数据流

数组就是一个最简单的数据流,数组内的值是连续的。而基于时间变化的数据流在一个事件范围内以离散形式存在。如鼠标的点击事件,我们将点击鼠标的事件采集起来就能够得到一个基于时间变化的数据流。如图:

多维数组 & 多维数据流

C语言中数组内的元素可以是数组形成多维数组。相似的数据流内元素也可以是一个数据流形成多维数据流,如图:

数据流的操作

RAC提供了对数据流的组合和变换,我们可以对数据流进行一定的操作得到新的流如:

  • 对值操作得到新的流
  • 对值的数量进行操作得到新的流
  • 对维度操作得到新的流
  • 对时间间隔进行操作得到新的流

除此之外我们还可以对多个流进行合并、变换等操作

RAC的核心组件

这里对RAC的核心组件做简要介绍,在后续的学习过程中会做更深入整理

RACSteam

RACSteam是RAC对数据流的抽象,提供了一些抽象的接口,其功能主要体现在其两个子类RACSignal(离散数据流)和RACSequence(连续数据流)。

我们从两个角度分析一个RACSignal 和 RACSequence

Data vs Event

RACSequence:处理的是数据,表示一个序列,里面存放的是一系列的数据,类似数组。
RACSignal:处理的是事件,值事件、错误事件、终止事件。

pullDriver vs pushDriver

RACSignal的数据驱动类型是pushDriver;那么什么是pushDriver?

  • 从值的创建角度:pushDriver意味着信号的值在创建时没有被定义,并可能在稍后的时间里产生信号的值。例如:网络请求或任何用户输入。
  • 从值的传递角度:每当产生新的信号都会,信号源就会给订阅者发送数据。对于数据调取者是被动接受的。

RACSequence的数据驱动类型是pullDriver;那么什么是pullDriver?

  • 从值的创建角度:pullDriver意味着信号的值在创建的时候就被定义。例如:数组里的值。
  • 从值的传递角度:任何时间想要拿到数据调取者都可以从数据流里拉取数据。整个时间控制掌握在调取者手中。

pushDriver可以理解为看电视,pullDriver可以理解为看书。

RACSubscriber

RACSubscriber对象是RACSignal的订阅者,负责处理RACSignal传出的数据。RACSubscriber对象初始化的时候回传入的nextBlock、 errorBlock、completeBlock分别处理RACSignal的值事件、错误事件、终止事件。

RACDisposable

RACSubscriber在对事件进行订阅时会返回RACDisposable对象,可以通过RACDisposable来终止对信号的订阅。

RACScheduler

RACScheduler底层是RAC对GCD的封装,是RAC中负责任务调度的调度器。 RACScheduler通过对GCD封装让并发编程与RAC高度整合。使RAC的使用者更畅快的沉浸在FRP的世界里。

相关链接

响应式编程介绍
函数式响应型编程(Functional Reactive Programming)会在什么问题上有优势?
What is the difference between RACSequence and RACSignal

如果对你有帮助的话,Star✨下一吧!