便利函数(SupportCode)
在进入正题之前,先看下项目里的 SupportCode.swift ,主要为 playground 提供了两个便利函数。
一个是 example 函数,专门用来写示例代码的,统一输出 log 便于标记浏览,同时还能保持变量不污染全局:
1  | public func example(description: String, action: () -> ()) {  | 
另一个是 delay 函数,通过 dispatch_after 用来演示延时的:
1  | public func delay(delay:Double, closure:()->()) {  | 
前言(Introduction)
主要介绍了 Rx 的基础: Observable 。
Observable
事件信息分为三种:
- Next(value) 表示新的事件数据。
 - Completed 表示事件序列的完结。
 - Error 同样表示完结,但是代表异常导致的完结。
 
被观察者(Observable)
empty
empty 是一个空的序列,它只发送 .Completed 消息。
1  | example("empty") {  | 
never
never 是没有任何元素、也不会发送任何事件的空序列。
1  | example("never") {  | 
just
just 是只包含一个元素的序列,它会先发送 .Next(value) ,然后发送 .Completed 。
1  | example("just") {  | 
sequenceOf
sequenceOf 可以把一系列元素转换成事件序列。
1  | example("sequenceOf") {  | 
form
form 是通过 asObservable() 方法把 Swift 中的序列 (SequenceType) 转换成事件序列。
1  | example("from") {  | 
create
create 可以通过闭包创建序列,通过 .on(e: Event) 添加事件。
1  | example("create") {  | 
failWith
failWith 创建一个没有元素的序列,只会发送失败 (.Error) 事件。
1  | example("failWith") {  | 
deferred
deferred 会等到有订阅者的时候再通过工厂方法创建 Observable 对象,每个订阅者订阅的对象都是内容相同而完全独立的序列。
1  | example("deferred") {  | 
为什么需要 defferd 这样一个奇怪的家伙呢?其实这相当于是一种延时加载,因为在添加监听的时候数据未必加载完毕,例如下面这个例子:
1  | example("TestDeferred") {  | 
如果使用 deffered 则可以正常显示想要的数据:
1  | example("TestDeferred") {  | 
代理和桥梁(Subjects)
接下来是关于 Subject 的内容。 Subject 可以看做是一种代理和桥梁。它既是订阅者又是订阅源,这意味着它既可以订阅其他 Observable 对象,同时又可以对它的订阅者们发送事件。
如果把 Observable 理解成不断输出事件的水管,那 Subject 就是套在上面的水龙头。它既怼着一根不断出水的水管,同时也向外面输送着新鲜水源。如果你直接用水杯接着水管的水,那可能导出来什么王水胶水完全把持不住;如果你在水龙头下面接着水,那你可以随心所欲的调成你想要的水速和水温。
(好吧上面一段文档里没有,是我瞎掰的,如果理解错了还望打脸( ̄ε(# ̄)☆╰╮( ̄▽ ̄///))
在开始下面的代码之前,先定义一个辅助函数用于输出数据:
1  | func writeSequenceToConsole<O: ObservableType>(name: String, sequence: O) {  | 
PublishSubject
PublishSubject 会发送订阅者从订阅之后的事件序列。
1  | example("PublishSubject") {  | 
ReplaySubject
ReplaySubject 在新的订阅对象订阅的时候会补发所有已经发送过的数据队列, bufferSize 是缓冲区的大小,决定了补发队列的最大值。
如果 bufferSize 是1,那么新的订阅者出现的时候就会补发上一个事件,如果是2,则补两个,以此类推。
1  | example("ReplaySubject") {  | 
BehaviorSubject
BehaviorSubject 在新的订阅对象订阅的时候会发送最近发送的事件,如果没有则发送一个默认值。
1  | example("BehaviorSubject") {  | 
Variable
Variable 是基于 BehaviorSubject 的一层封装,它的优势是:不会被显式终结。即:不会收到 .Completed 和 .Error 这类的终结事件,它会主动在析构的时候发送 .Complete。
1  | example("Variable") {  | 
转换(Transform)
我们可以对序列做一些转换,类似于 Swift 中 CollectionType 的各种转换。在以前的坑中曾经提到过,可以参考:函数式的函数。
map
map 就是对每个元素都用函数做一次转换,挨个映射一遍。
1  | example("map") {  | 
flatMap
map 在做转换的时候很容易出现『升维』的情况,即:转变之后,从一个序列变成了一个序列的序列。
什么是『升维』?在集合中我们可以举这样一个例子,我有一个好友列表 [p1, p2, p3],那么如果要获取我好友的好友的列表,可以这样做:
myFriends.map { $0.getFriends() }
结果就成了 [[p1-1, p1-2, p1-3], [p2-1], [p3-1, p3-2]] ,这就成了好友的好友列表的列表了。这就是一个『升维』的例子。
在 Swift 中,我们可以用 flatMap 过滤掉 map 之后的 nil 结果。
在 Rx 中, flatMap 可以把一个序列转换成一组序列,然后再把这一组序列『拍扁』成一个序列。
1  | example("flatMap") {  | 
scan
scan 有点像 reduce ,它会把每次的运算结果累积起来,作为下一次运算的输入值。 
1  | example("scan") {  | 
过滤(Filtering)
除了上面的各种转换,我们还可以对序列进行过滤。
filter
filter 只会让符合条件的元素通过。
1  | example("filter") {  | 
distinctUntilChanged
distinctUntilChanged 会废弃掉重复的事件。 
1  | example("distinctUntilChanged") {  | 
take
take 只获取序列中的前 n 个事件,在满足数量之后会自动 .Completed 。
1  | example("take") {  | 
运算(Combining)
这部分是关于序列的运算,可以将多个序列源进行组合拼装成一个新的事件序列。
startWith
startWith 会在队列开始之前插入一个事件元素。 
1  | example("startWith") {  | 
combineLatest
如果存在两条事件队列,需要同时监听,那么每当有新的事件发生的时候,combineLatest 会将每个队列的最新的一个元素进行合并。
1  | example("combineLatest 1") {  | 
zip
zip 人如其名,就是压缩两条队列用的,不过它会等到两个队列的元素一一对应地凑齐了之后再合并。 
1  | example("zip 1") {  | 
marge
merge 就是把两个队列按照顺序组合在一起。
1  | example("merge 1") {  | 
switch
当你的事件序列是一个事件序列的序列 (Observable<Observable
和 merge 相似的是,它也是起到了将多个序列『拍平』成一条序列的作用。
1  | example("switchLatest") {  | 
注意,虽然都是『拍平』,但是和 flatmap 是不同的, flatmap 是将一条序列变成另一条序列,而这变换过程会让维度变高,所以需要『拍平』,而 switch 是将本来二维的序列(序列的序列)拍平成了一维的序列。
异常处理(Error Handling)
在事件序列中,遇到异常也是很正常的事情,有以下几种处理异常的手段。
catchError
catchError 可以捕获异常事件,并且在后面无缝接上另一段事件序列,丝毫没有异常的痕迹。
1  | example("catchError 1") {  | 
retry
retry 顾名思义,就是在出现异常的时候会再去从头订阅事件序列,妄图通过『从头再来』解决异常。
1  | example("retry") {  | 
事件订阅(Utility)
这里列举了针对事件序列的一些方法。
subscribe
subscribe 在前面已经接触过了,有新的事件就会触发。
1  | example"subscribe") {  | 
subscribeNext
subscribeNext 也是订阅,但是只订阅 .Next 事件。 
1  | example("subscribeNext") {  | 
subscribeCompleted
subscribeCompleted 是只订阅 .Completed 完成事件。 
1  | example("subscribeCompleted") {  | 
subscribeError
subscribeError 只订阅 .Error 失败事件。 
1  | example("subscribeError") {  | 
doOn
doOn 可以监听事件,并且在事件发生之前调用。 
1  | example("doOn") {  | 
逻辑判断(Conditional)
我们可以对多个事件序列做一些复杂的逻辑判断。
takeUntil
takeUntil 其实就是 take ,它会在终于等到那个事件之后触发 .Completed 事件。
1  | example("takeUntil") {  | 
takeWhile
takeWhile 则是可以通过状态语句判断是否继续 take 。
1  | example("takeWhile") {  | 
集合运算(Aggregate)
我们可以对事件序列做一些集合运算。
concat
concat 可以把多个事件序列合并起来。
1  | example("concat") {  | 
reduce
这里的 reduce 和 CollectionType 中的 reduce 是一个意思,都是指通过对一系列数据的运算最后生成一个结果。
example("reduce") { 
    sequenceOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 
        .reduce(0, +) 
        .subscribe { 
            print($0) 
        } 
} 
--- reduce example --- 
Next(45) 
Completed
另外附上我在实际应用中的示例