框架概览
本文档从高层次描述ReactiveCocoa框架中不同的组成部分,并尝试解释他们是如何配合工作和分工的。本篇文档作为学习新模块和更具体文档的起点。
如果是为了寻找例子或者理解RAC的用法的话,请阅读README或者Design Guidelines.
流(Streams)
RACStream抽象类代表了一个流,是由一些对象值所组成的任意序列。
值可能马上或者在将来某个时刻变得可用,但是每个值必须按顺序检索。在检索流中的第二个值之前,你必须对流中的第一个值进行处理。
流是单子(monads)。除了其他方面,这将允许将许多复杂的操作建立在一些原始的操作上(特别是-bind:
操作)。RACStream的实现相当于Haskell中的Monoid和MonadZip的typeclasses.
RACStream本身作用并不大。大部分流其实都被当做了信号或者序列。
信号(Signals)
一个RACSignal类对象代表了一个信号,是一个推动式( push-driven )的流。
信号通常都代表了将来会被送达的数据。比如一个方法被调用或者收到了数据,值在信号中被 发送( sent ),信号将会把他们‘推给’任何订阅者。用户必须订阅一个信号来获取它里面的值。
信号会发送三种不同的事件给它的订阅者:
next将会从流中获得一个新的值。RACStream只会操作此种类型的事件。和Cocoa中的集合类 型不同,信号中包含一个
nil
也是合法的。error事件表明一个错误在信号发出之前产生。这个时间可能会包含一个
NSError
对象,表明发生 了什么错误。错误必须被特殊处理-他们不被包含在流的值当中。- completed事件表明这个信号成功完成了发送,这个流将不会再有更多地值。完成事件必须被特殊处 理-它不被包含在流的值当中。
一个信号的完整生命周期中可能包含多个next
事件,接着可能是一个error
或者completed
事件。
订阅(Subscription)
一个订阅者可以是任何正在等待或者能够获取[信号][#信号]中的事件的对象。在RAC当中,订阅者是任何实现了RACSubscriber协议的对象。
通过-subscribeNext:error:completed:或者对应的方便方法可以产生一个订阅。从技术上来说,大部分RACStream和RACSignal的操作符也会产生订阅,但是它们都是中间层的订阅,属于框架实现的细节。
订阅会将信号retain,并会在信号完成发送或者产生错误的时候被析构(disposed)。订阅也可被手动析构
Subjects
一个subject,代表一个RACSubject类对象,是一种可以手动控制的信号。
Subjects可以被认为是一种”可变(mutable)”的信号,就像NSMutableArray
和NSArray
。Subjects对于将非RAC的变得RAC非常有用。
比如,我们可以不用在block当中处理程序的回调,这些block可以将事件通过一个subject单例发送出去。这个subject可以以一个RACSignal的形式返回,并隐藏掉这些回调的实现细节。
一些subjects也提供了特殊的行为。特别是RACReplaySubject可以被用来将事件缓存给将来的订阅者,比如将一个网络请求的结果缓存并等待其他的对象准备好处理它。
Commands
一个command,代表一个RACCommand对象,创建并订阅一个信号以响应一些动作。动作使得一些会产生副作用的行为变得十分简单,比如用户操作App。
通常情况下一个command被UI事件触发,比如一个按钮被点击。Commands也可以通过一个信号来自动的被禁用或者可用,而且这个禁用状态也可以通过将和这个command相关的UI控件禁用来体现。
在OS X中,RAC通过NSButton来添加一个rac_command属性来自动支持这些行为。
连接(Connections)
一个连接,代表一个RACMulticastConnection对象,是一个可以被多个订阅者分享的[订阅][#订阅]。
信号在默认情况下都是 冷 的,这表明它们 每次 在一个新的订阅产生时都会工作一次。但是这种特性常常都不是我们想要的,因为这意味着每当一个新的订阅产生时都会将信号中的值重新计算一次,如果这个信号有副作用或者工作量很大的话(比如,发送一个网络请求)就会产生较大的问题。
我们通过RACSignal中的 -publish
或者 -multicast:
方法来创建一个连接,并确保无论有多少个订阅者订阅了这个连接,都只有一个内部的订阅被创建。当连接建立了之后,这个连接的信号就是 热 的,并且内部的订阅会一直保持活跃直到 所有 对这个连接的订阅被[析构][#析构]。
序列 (Sequences)
一个序列代表一个RACSequence对象,是一个 拉动式 的流。
序列一种集合,类似于 NSArray
。和数组不同的是,序列中的值默认是 懒 演算的。(比如,当他们被需要时),这样就能在序列中只有一部分的值被使用的时候提升性能。和Cocoa的集合类型一样,序列中也不能包含 nil
。
序列和 Clojure’s sequences(特别是lazy-seq)或者Haskell中的 List很像。
RAC给Cocoa中的大部分集合类型都添加了 -rac_sequence
方法,来让他们像 RACSequences 一样被使用。
析构(Disposables)
RACDisposable类对象被用来取消任务和清除资源。
析构被用来取消对一个信号的订阅。当一个订阅被取消时,相应的订阅者将不会再收到 任何 来自这个信号的事件。并且,任何和这个订阅相关的工作(后台处理,网络请求,等等。)都会被取消,因为这些结果都已经不需要了。
查看更多关于取消订阅的内容,请阅读RACDesign Guidelines。
Schedulers
一个scheduler代表一个RACScheduler类对象,是一个顺序执行信号的队列,来开展他们的工作或者传递它们的结果。
Schedulers和GCD类似,但是schedulers支持取消(通过析构),而且一定是顺序执行的。除了 +immediateScheduler之外,schedulers不提供任何同步执行的方法。这有助于避免死锁,我们鼓励使用signal operators而不是阻塞工作。
RACScheduler也和NSOperationQueue
类似,但是schedulers并不支持任务的重新排序或者任务间的相互依赖。
值类型 (Value types)
RAC提供一些通用的类,以让值在流中被传递: