|
| 1 | +# 框架概览 |
| 2 | + |
| 3 | +本文档从高层次描述ReactiveCocoa框架中不同的组成部分,并尝试解释他们是如何配合工作和分工的。本篇文档作为学习新模块和更具体文档的起点。 |
| 4 | + |
| 5 | +如果是为了寻找例子或者理解RAC的用法的话,请阅读[README][]或者[Design Guidelines][]. |
| 6 | + |
| 7 | +## 流(Streams) |
| 8 | + |
| 9 | +[RACStream][]抽象类代表了一个**流**,是由一些对象值所组成的任意序列。 |
| 10 | + |
| 11 | +值可能马上或者在将来某个时刻变得可用,但是每个值必须按顺序检索。在检索流中的第二个值之前,你必须对流中的第一个值进行处理。 |
| 12 | + |
| 13 | +流是单子([monads][])。除了其他方面,这将允许将许多复杂的操作建立在一些原始的操作上(特别是`-bind:`操作)。[RACStream][]的实现相当于[Haskell][]中的[Monoid][]和[MonadZip][]的typeclasses. |
| 14 | + |
| 15 | +[RACStream][]本身作用并不大。大部分流其实都被当做了[信号](#信号)或者[序列](#序列)。 |
| 16 | + |
| 17 | +##信号(Signals) |
| 18 | + |
| 19 | +一个[RACSignal][]类对象代表了一个**信号**,是一个推动式( _push-driven_ )的[流](#流)。 |
| 20 | + |
| 21 | +信号通常都代表了将来会被送达的数据。比如一个方法被调用或者收到了数据,值在信号中被 _发送_( _sent_ ),信号将会把他们‘推给’任何订阅者。用户必须[订阅](#订阅)一个信号来获取它里面的值。 |
| 22 | + |
| 23 | +信号会发送三种不同的事件给它的订阅者: |
| 24 | + |
| 25 | + * **next**将会从流中获得一个新的值。[RACStream][]只会操作此种类型的事件。和Cocoa中的集合类 型不同,信号中包含一个`nil`也是合法的。 |
| 26 | + |
| 27 | + * **error**事件表明一个错误在信号发出之前产生。这个时间可能会包含一个`NSError`对象,表明发生 了什么错误。错误必须被特殊处理-他们不被包含在流的值当中。 |
| 28 | + * |
| 29 | + * **completed**事件表明这个信号成功完成了发送,这个流将不会再有更多地值。完成事件必须被特殊处 理-它不被包含在流的值当中。 |
| 30 | +一个信号的完整生命周期中可能包含多个`next`事件,接着可能是一个`error`或者`completed`事件。 |
| 31 | + |
| 32 | +###订阅(Subscription) |
| 33 | + |
| 34 | +一个**订阅者**可以是任何正在等待或者能够获取[信号][#信号]中的事件的对象。在RAC当中,订阅者是任何实现了[RACSubscriber][]协议的对象。 |
| 35 | + |
| 36 | +通过[-subscribeNext:error:completed:][RACSignal]或者对应的方便方法可以产生一个订阅。从技术上来说,大部分[RACStream][]和[RACSignal][RACsignal+Operations]的操作符也会产生订阅,但是它们都是中间层的订阅,属于框架实现的细节。 |
| 37 | + |
| 38 | +订阅会将信号[retain][Memory Management],并会在信号完成发送或者产生错误的时候被析构(disposed)。订阅也可被手动[析构](#析构) |
| 39 | + |
| 40 | +### Subjects |
| 41 | + |
| 42 | +一个**subject**,代表一个[RACSubject][]类对象,是一种可以手动控制的[信号](#signals)。 |
| 43 | + |
| 44 | +Subjects可以被认为是一种"可变(mutable)"的信号,就像`NSMutableArray`和`NSArray`。Subjects对于将非RAC的变得RAC非常有用。 |
| 45 | + |
| 46 | +比如,我们可以不用在block当中处理程序的回调,这些block可以将事件通过一个subject单例发送出去。这个subject可以以一个[RACSignal][]的形式返回,并隐藏掉这些回调的实现细节。 |
| 47 | + |
| 48 | +一些subjects也提供了特殊的行为。特别是[RACReplaySubject][]可以被用来将事件缓存给将来的[订阅者](#订阅),比如将一个网络请求的结果缓存并等待其他的对象准备好处理它。 |
| 49 | + |
| 50 | +### Commands |
| 51 | + |
| 52 | +一个**command**,代表一个[RACCommand][]对象,创建并订阅一个信号以响应一些动作。动作使得一些会产生副作用的行为变得十分简单,比如用户操作App。 |
| 53 | + |
| 54 | +通常情况下一个command被UI事件触发,比如一个按钮被点击。Commands也可以通过一个信号来自动的被禁用或者可用,而且这个禁用状态也可以通过将和这个command相关的UI控件禁用来体现。 |
| 55 | + |
| 56 | +在OS X中,RAC通过[NSButton][NSButton+RACCommandSupport]来添加一个rac_command属性来自动支持这些行为。 |
| 57 | + |
| 58 | +### 连接(Connections) |
| 59 | + |
| 60 | +一个**连接**,代表一个[RACMulticastConnection]对象,是一个可以被多个订阅者分享的[订阅][#订阅]。 |
| 61 | + |
| 62 | +[信号](#信号)在默认情况下都是 _冷_ 的,这表明它们 _每次_ 在一个新的订阅产生时都会工作一次。但是这种特性常常都不是我们想要的,因为这意味着每当一个新的订阅产生时都会将信号中的值重新计算一次,如果这个信号有副作用或者工作量很大的话(比如,发送一个网络请求)就会产生较大的问题。 |
| 63 | + |
| 64 | +我们通过[RACSignal][RACSignal+Operations]中的 `-publish` 或者 `-multicast:` 方法来创建一个连接,并确保无论有多少个订阅者订阅了这个连接,都只有一个内部的订阅被创建。当连接建立了之后,这个连接的信号就是 _热_ 的,并且内部的订阅会一直保持活跃直到 _所有_ 对这个连接的订阅被[析构][#析构]。 |
| 65 | + |
| 66 | +## 序列 (Sequences) |
| 67 | + |
| 68 | +一个**序列**代表一个[RACSequence][]对象,是一个 _拉动式_ 的[流](#流)。 |
| 69 | + |
| 70 | +序列一种集合,类似于 `NSArray`。和数组不同的是,序列中的值默认是 _懒_ 演算的。(比如,当他们被需要时),这样就能在序列中只有一部分的值被使用的时候提升性能。和Cocoa的集合类型一样,序列中也不能包含 `nil`。 |
| 71 | + |
| 72 | +序列和 [Clojure's sequences][seq](特别是[lazy-seq][])或者[Haskell][]中的 [List][]很像。 |
| 73 | + |
| 74 | +RAC给Cocoa中的大部分集合类型都添加了 `-rac_sequence` 方法,来让他们像 [RACSequences][RACSequence] 一样被使用。 |
| 75 | + |
| 76 | +## 析构(Disposables) |
| 77 | + |
| 78 | +**[RACDisposable][]**类对象被用来取消任务和清除资源。 |
| 79 | + |
| 80 | +析构被用来取消对一个[信号](#信号)的订阅。当一个[订阅](#订阅)被取消时,相应的订阅者将不会再收到 _任何_ 来自这个信号的事件。并且,任何和这个订阅相关的工作(后台处理,网络请求,等等。)都会被取消,因为这些结果都已经不需要了。 |
| 81 | + |
| 82 | +查看更多关于取消订阅的内容,请阅读RAC[Design Guidelines][]。 |
| 83 | + |
| 84 | +## Schedulers |
| 85 | + |
| 86 | +一个**scheduler**代表一个[RACScheduler][]类对象,是一个顺序执行[信号](#signals)的队列,来开展他们的工作或者传递它们的结果。 |
| 87 | + |
| 88 | +Schedulers和GCD类似,但是schedulers支持取消(通过[析构](#析构)),而且一定是顺序执行的。除了 [+immediateScheduler][RACScheduler]之外,schedulers不提供任何同步执行的方法。这有助于避免死锁,我们鼓励使用[signal operators][RACSignal+Operations]而不是阻塞工作。 |
| 89 | + |
| 90 | +[RACScheduler][]也和`NSOperationQueue`类似,但是schedulers并不支持任务的重新排序或者任务间的相互依赖。 |
| 91 | + |
| 92 | +## 值类型 (Value types) |
| 93 | + |
| 94 | +RAC提供一些通用的类,以让值在[流](#流)中被传递: |
| 95 | + |
| 96 | + * **[RACTuple][]** 是一个小巧的,constant-sized的集合类型,并可以包含`nil`(以`RACTupleNil`表示)。它通常被用来合并多个流中的值。 |
| 97 | + * **[RACUnit][]**是一个'空'值单例,当一个流中没有有意义的值存在时,并且流没有被关闭时,流使用这个值来表示无意义。 |
| 98 | + * **[RACEvent][]**将[信号事件](#信号)转化为一个值。它主要被[RACSignal][RACSignal+Operations]中的`-materialize` 方法使用。 |
| 99 | + |
| 100 | +[Design Guidelines]: DesignGuidelines.md |
| 101 | +[Haskell]: http://www.haskell.org |
| 102 | +[lazy-seq]: http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/lazy-seq |
| 103 | +[List]: https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.7.0.2/Data-List.html |
| 104 | +[Memory Management]: MemoryManagement.md |
| 105 | +[monads]: http://en.wikipedia.org/wiki/Monad_(functional_programming) |
| 106 | +[Monoid]: http://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.7.0.2/Data-Monoid.html |
| 107 | +[MonadZip]: http://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.7.0.2/Control-Monad-Zip.html |
| 108 | +[NSButton+RACCommandSupport]: ../ReactiveCocoa/NSButton+RACCommandSupport.h |
| 109 | +[RACCommand]: ../ReactiveCocoa/RACCommand.h |
| 110 | +[RACDisposable]: ../ReactiveCocoa/RACDisposable.h |
| 111 | +[RACEvent]: ../ReactiveCocoa/RACEvent.h |
| 112 | +[RACMulticastConnection]: ../ReactiveCocoa/RACMulticastConnection.h |
| 113 | +[RACReplaySubject]: ../ReactiveCocoa/RACReplaySubject.h |
| 114 | +[RACScheduler]: ../ReactiveCocoa/RACScheduler.h |
| 115 | +[RACSequence]: ../ReactiveCocoa/RACSequence.h |
| 116 | +[RACSignal]: ../ReactiveCocoa/RACSignal.h |
| 117 | +[RACSignal+Operations]: ../ReactiveCocoa/RACSignal+Operations.h |
| 118 | +[RACStream]: ../ReactiveCocoa/RACStream.h |
| 119 | +[RACSubject]: ../ReactiveCocoa/RACSubject.h |
| 120 | +[RACSubscriber]: ../ReactiveCocoa/RACSubscriber.h |
| 121 | +[RACTuple]: ../ReactiveCocoa/RACTuple.h |
| 122 | +[RACUnit]: ../ReactiveCocoa/RACUnit.h |
| 123 | +[README]: ../README.md |
| 124 | +[seq]: http://clojure.org/sequences |
0 commit comments