大神都在看的RxSwift 的完全入坑手冊

大神都在看的RxSwift 的完全入坑手冊

2015-09-24 18:25 CallMeWhy callmewhy 字號:T | T
一鍵收藏,隨時查看,分享好友!

我主要是通過項目裏的 Rx.playground 進行學習和了解的,這種方式確實便捷高效。只需要把文檔用 /*: */ 註釋即可,直接用 Markdown 編寫,簡單方便。不過 Xcode7 中這種方式現在還不是很穩定,會有大量的空行,而且有個最大的問題就是閱讀到中間然後切到其他文件再切回來的時候,閱讀的進度條是從頭開始的,並不能記錄上次閱讀的位置。心累。............

AD:51CTO技術沙龍 | 賦予APP不同凡響的交互和體驗>>

RxSwift 是我在 Github 上關注已久的一個項目,今天花點時間過了一下它的示例代碼,感覺很有意思。

我主要是通過項目裏的 Rx.playground 進行學習和了解的,這種方式確實便捷高效。只需要把文檔用 /*: */ 註釋即可,直接用 Markdown 編寫,簡單方便。不過 Xcode7 中這種方式現在還不是很穩定,會有大量的空行,而且有個最大的問題就是閱讀到中間然後切到其他文件再切回來的時候,閱讀的進度條是從頭開始的,並不能記錄上次閱讀的位置。心累。

下面是我的簡單筆記,只是把學習過程中的收穫記錄下來,大部分內容來自於項目內的 playground 。注意!是很大部分!而且操場裏圖文並茂,很容易理解。所以,各位如果感興趣,建議 clone 官方項目,跑個操場玩玩。

參考文獻中羅列了我在學習過程中查閱的相關資料,可以作爲補充閱讀。

SupportCode

在進入正題之前,先看下項目裏的 SupportCode.swift ,主要爲 playground 提供了兩個便利函數。

一個是 example 函數,專門用來寫示例代碼的,統一輸出 log 便於標記瀏覽,同時還能保持變量不污染全局:

  1. public func example(description: String, action: () -> ()) { 
  2.     print("\n--- \(description) example ---"
  3.     action() 

另一個是 delay 函數,通過 dispatch_after 用來演示延時的:

  1. public func delay(delay:Double, closure:()->()) { 
  2.     dispatch_after( 
  3.         dispatch_time( 
  4.             DISPATCH_TIME_NOW, 
  5.             Int64(delay * Double(NSEC_PER_SEC)) 
  6.         ), 
  7.         dispatch_get_main_queue(), closure) 

Introduction

主要介紹了 Rx 的基礎: Observable 。 Observable<Element> 是觀察者模式中被觀察的對象,相當於一個事件序列 (GeneratorType) ,會向訂閱者發送新產生的事件信息。事件信息分爲三種:

  • .Next(value) 表示新的事件數據。
  • .Completed 表示事件序列的完結。
  • .Error 同樣表示完結,但是代表異常導致的完結。

(打個岔:協議命名,想起來上午湯哥在微博說的一段話:

另外,我覺得 protocol 名字用形容詞會更加語義分明,比如 Swift : Flyable, Killable, Visible。全用名詞的話顯得比較生硬,比如 Swift : Head, Wings, Ass。

empty

empty 是一個空的序列,它只發送 .Completed 消息。

  1. example("empty") { 
  2.     let emptySequence: Observable<Int> = empty() 
  3.  
  4.     let subscription = emptySequence 
  5.         .subscribe { event in 
  6.             print(event) 
  7.         } 
  8.  
  9. --- empty example --- 
  10. Completed 

never

never 是沒有任何元素、也不會發送任何事件的空序列。

  1. example("never") { 
  2.     let neverSequence: Observable<String> = never() 
  3.  
  4.     let subscription = neverSequence 
  5.         .subscribe { _ in 
  6.             print("This block is never called."
  7.         } 
  8.  
  9. --- never example --- 

just

just 是隻包含一個元素的序列,它會先發送 .Next(value) ,然後發送 .Completed 。

  1. example("just") { 
  2.     let singleElementSequence = just(32
  3.  
  4.     let subscription = singleElementSequence 
  5.         .subscribe { event in 
  6.             print(event) 
  7.         } 
  8.  
  9. --- just example --- 
  10. Next(32
  11. Completed 

sequenceOf

sequenceOf 可以把一系列元素轉換成事件序列。

 
  1. example("sequenceOf") { 
  2.     let sequenceOfElements/* : Observable<Int> */ = sequenceOf(0123
  3.  
  4.     let subscription = sequenceOfElements 
  5.         .subscribe { event in 
  6.             print(event) 
  7.         } 
  8.  
  9. --- sequenceOf example --- 
  10. Next(0
  11. Next(1
  12. Next(2
  13. Next(3
  14. Completed 

form

form 是通過 asObservable() 方法把 Swift 中的序列 (SequenceType) 轉換成事件序列。

  1. example("from") { 
  2.     let sequenceFromArray = [12345].asObservable() 
  3.  
  4.     let subscription = sequenceFromArray 
  5.         .subscribe { event in 
  6.             print(event) 
  7.         } 
  8.  
  9. --- from example --- 
  10. Next(1
  11. Next(2
  12. Next(3
  13. Next(4
  14. Next(5
  15. Completed 

create

create 可以通過閉包創建序列,通過 .on(e: Event) 添加事件。

  1. example("create") { 
  2.     let myJust = { (singleElement: Int) -> Observable<Int> in 
  3.         return create { observer in 
  4.             observer.on(.Next(singleElement)) 
  5.             observer.on(.Completed) 
  6.  
  7.             return NopDisposable.instance 
  8.         } 
  9.     } 
  10.  
  11.     let subscription = myJust(5
  12.         .subscribe { event in 
  13.             print(event) 
  14.         } 
  15.  
  16. --- create example --- 
  17. Next(5
  18. Completed 

failWith

failWith 創建一個沒有元素的序列,只會發送失敗 (.Error) 事件。

  1. example("failWith") { 
  2.     let error = NSError(domain: "Test", code: -1, userInfo: nil) 
  3.  
  4.     let erroredSequence: Observable<Int> = failWith(error) 
  5.  
  6.     let subscription = erroredSequence 
  7.         .subscribe { event in 
  8.             print(event) 
  9.         } 
  10.  
  11. --- failWith example --- 
  12. Error(Error Domain=Test Code=-1 "The operation couldn’t be completed. (Test error -1.)"

deferred

deferred 會等到有訂閱者的時候再通過工廠方法創建 Observable 對象,每個訂閱者訂閱的對象都是內容相同而完全獨立的序列。

  1. example("deferred") { 
  2.     let deferredSequence: Observable<Int> = deferred { 
  3.         print("creating"
  4.         return create { observer in 
  5.             print("emmiting"
  6.             observer.on(.Next(0)) 
  7.             observer.on(.Next(1)) 
  8.             observer.on(.Next(2)) 
  9.  
  10.             return NopDisposable.instance 
  11.         } 
  12.     } 
  13.  
  14.     print("go"
  15.  
  16.     deferredSequence 
  17.         .subscribe { event in 
  18.             print(event) 
  19.     } 
  20.  
  21.     deferredSequence 
  22.         .subscribe { event in 
  23.             print(event) 
  24.         } 
  25.  
  26. --- deferred example --- 
  27. go 
  28. creating 
  29. emmiting 
  30. Next(0
  31. Next(1
  32. Next(2
  33. creating 
  34. emmiting 
  35. Next(0
  36. Next(1
  37. Next(2

爲什麼需要 defferd 這樣一個奇怪的傢伙呢?其實這相當於是一種延時加載,因爲在添加監聽的時候數據未必加載完畢,例如下面這個例子:

  1. example("TestDeferred") { 
  2.     var value: String? = nil 
  3.     var subscription: Observable<String?> = just(value) 
  4.  
  5.     // got value 
  6.     value = "Hello!" 
  7.  
  8.     subscription.subscribe { event in 
  9.         print(event) 
  10.     } 
  11.  
  12. --- TestDeferred example --- 
  13. Next(nil) 
  14. Completed 

如果使用 deffered 則可以正常顯示想要的數據:

  1. example("TestDeferred") { 
  2.     var value: String? = nil 
  3.     var subscription: Observable<String?> = deferred { 
  4.         return just(value) 
  5.     } 
  6.  
  7.     // got value 
  8.     value = "Hello!" 
  9.  
  10.     subscription.subscribe { event in 
  11.         print(event) 
  12.     } 
  13.  
  14.  
  15. --- TestDeferred example --- 
  16. Next(Optional("Hello!")) 
  17. Completed 

Subjects

接下來是關於 Subject 的內容。 Subject 可以看做是一種代理和橋樑。它既是訂閱者又是訂閱源,這意味着它既可以訂閱其他 Observable 對象,同時又可以對它的訂閱者們發送事件。

如果把 Observable 理解成不斷輸出事件的水管,那 Subject 就是套在上面的水龍頭。它既懟着一根不斷出水的水管,同時也向外面輸送着新鮮水源。如果你直接用水杯接着水管的水,那可能導出來什麼王水膠水完全把持不住;如果你在水龍頭下面接着水,那你可以隨心所欲的調成你想要的水速和水溫。

(好吧上面一段文檔裏沒有,是我瞎掰的,如果理解錯了還望打臉( ̄ε(# ̄)☆╰╮( ̄▽ ̄///))

在開始下面的代碼之前,先定義一個輔助函數用於輸出數據:

  1. func writeSequenceToConsole<O: ObservableType>(name: String, sequence: O) { 
  2.     sequence 
  3.         .subscribe { e in 
  4.             print("Subscription: \(name), event: \(e)"
  5.         } 

PublishSubject

PublishSubject 會發送訂閱者從訂閱之後的事件序列。

  1. example("PublishSubject") { 
  2.     let subject = PublishSubject<String>() 
  3.     writeSequenceToConsole("1", sequence: subject) 
  4.     subject.on(.Next("a")) 
  5.     subject.on(.Next("b")) 
  6.     writeSequenceToConsole("2", sequence: subject) 
  7.     subject.on(.Next("c")) 
  8.     subject.on(.Next("d")) 
  9.  
  10.  
  11. --- PublishSubject example --- 
  12. Subscription: 1, event: Next(a) 
  13. Subscription: 1, event: Next(b) 
  14. Subscription: 1, event: Next(c) 
  15. Subscription: 2, event: Next(c) 
  16. Subscription: 1, event: Next(d) 
  17. Subscription: 2, event: Next(d) 

ReplaySubject

ReplaySubject 在新的訂閱對象訂閱的時候會補發所有已經發送過的數據隊列,bufferSize 是緩衝區的大小,決定了補發隊列的最大值。如果 bufferSize 是1,那麼新的訂閱者出現的時候就會補發上一個事件,如果是2,則補兩個,以此類推。

  1. example("ReplaySubject") { 
  2.     let subject = ReplaySubject<String>.create(bufferSize: 1
  3.  
  4.     writeSequenceToConsole("1", sequence: subject) 
  5.     subject.on(.Next("a")) 
  6.     subject.on(.Next("b")) 
  7.     writeSequenceToConsole("2", sequence: subject) 
  8.     subject.on(.Next("c")) 
  9.     subject.on(.Next("d")) 
  10.  
  11. --- ReplaySubject example --- 
  12. Subscription: 1, event: Next(a) 
  13. Subscription: 1, event: Next(b) 
  14. Subscription: 2, event: Next(b) // 補了一個 b 
  15. Subscription: 1, event: Next(c) 
  16. Subscription: 2, event: Next(c) 
  17. Subscription: 1, event: Next(d) 
  18. Subscription: 2, event: Next(d) 

BehaviorSubject

BehaviorSubject 在新的訂閱對象訂閱的時候會發送最近發送的事件,如果沒有則發送一個默認值。

  1. example("BehaviorSubject") { 
  2.     let subject = BehaviorSubject(value: "z"
  3.     writeSequenceToConsole("1", sequence: subject) 
  4.     subject.on(.Next("a")) 
  5.     subject.on(.Next("b")) 
  6.     writeSequenceToConsole("2", sequence: subject) 
  7.     subject.on(.Next("c")) 
  8.     subject.on(.Completed) 
  9.  
  10. --- BehaviorSubject example --- 
  11. Subscription: 1, event: Next(z) 
  12. Subscription: 1, event: Next(a) 
  13. Subscription: 1, event: Next(b) 
  14. Subscription: 2, event: Next(b) 
  15. Subscription: 1, event: Next(c) 
  16. Subscription: 2, event: Next(c) 
  17. Subscription: 1, event: Completed 
  18. Subscription: 2, event: Completed 

Variable

Variable 是基於 BehaviorSubject 的一層封裝,它的優勢是:不會被顯式終結。即:不會收到 .Completed 和 .Error 這類的終結事件,它會主動在析構的時候發送 .Complete 。

e 
  1. xample("Variable") { 
  2.     let variable = Variable("z"
  3.     writeSequenceToConsole("1", sequence: variable) 
  4.     variable.value = "a" 
  5.     variable.value = "b 
  6.     writeSequenceToConsole("2", sequence: variable) 
  7.     variable.value = "c" 
  8.  
  9. --- Variable example --- 
  10. Subscription: 1, event: Next(z) 
  11. Subscription: 1, event: Next(a) 
  12. Subscription: 1, event: Next(b) 
  13. Subscription: 2, event: Next(b) 
  14. Subscription: 1, event: Next(c) 
  15. Subscription: 2, event: Next(c) 
  16. Subscription: 1, event: Completed 
  17. Subscription: 2, event: Completed 

Transform

我們可以對序列做一些轉換,類似於 Swift 中 CollectionType 的各種轉換。在以前的坑中曾經提到過,可以參考:函數式的函數

map

map 就是對每個元素都用函數做一次轉換,挨個映射一遍。

  1. example("map") { 
  2.     let originalSequence = sequenceOf(1,2,3
  3.  
  4.     originalSequence 
  5.         .map { $0 * 2 } 
  6.         .subscribe { print($0) } 
  7.  
  8. --- map example --- 
  9. Next(2
  10. Next(4
  11. Next(6
  12. Completed 

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") { 
  2.     let sequenceInt = sequenceOf(123
  3.     let sequenceString = sequenceOf("A""B""--"
  4.  
  5.     sequenceInt 
  6.         .flatMap { int in 
  7.             sequenceString 
  8.         } 
  9.         .subscribe { 
  10.             print($0
  11.         } 
  12.  
  13. --- flatMap example --- 
  14. Next(A) 
  15. Next(B) 
  16. Next(--) 
  17. Next(A) 
  18. Next(B) 
  19. Next(--) 
  20. Next(A) 
  21. Next(B) 
  22. Next(--) 
  23. Completed 

scan

  1. scan 有點像 reduce ,它會把每次的運算結果累積起來,作爲下一次運算的輸入值。 
  2.  
  3. example("scan") { 
  4.     let sequenceToSum = sequenceOf(012345
  5.  
  6.     sequenceToSum 
  7.         .scan(0) { acum, elem in 
  8.             acum + elem 
  9.         } 
  10.         .subscribe { 
  11.             print($0
  12.         } 
  13.  
  14. --- scan example --- 
  15. Next(0
  16. Next(1
  17. Next(3
  18. Next(6
  19. Next(10
  20. Next(15
  21. Completed 

Filtering

除了上面的各種轉換,我們還可以對序列進行過濾。

filter

filter 只會讓符合條件的元素通過。

  1. example("filter") { 
  2.     let subscription = sequenceOf(0123456789
  3.         .filter { 
  4.             $0 % 2 == 0 
  5.         } 
  6.         .subscribe { 
  7.             print($0
  8.         } 
  9.  
  10. --- filter example --- 
  11. Next(0
  12. Next(2
  13. Next(4
  14. Next(6
  15. Next(8
  16. Completed 

distinctUntilChanged

  1. distinctUntilChanged 會廢棄掉重複的事件。 
  2.  
  3. example("distinctUntilChanged") { 
  4.     let subscription = sequenceOf(123114
  5.         .distinctUntilChanged() 
  6.         .subscribe { 
  7.             print($0
  8.         } 
  9.  
  10. --- distinctUntilChanged example --- 
  11. Next(1
  12. Next(2
  13. Next(3
  14. Next(1
  15. Next(4
  16. Completed 

take

take 只獲取序列中的前 n 個事件,在滿足數量之後會自動 .Completed 。

  1. example("take") { 
  2.     let subscription = sequenceOf(123456
  3.         .take(3
  4.         .subscribe { 
  5.             print($0
  6.         } 
  7.  
  8. --- take example --- 
  9. Next(1
  10. Next(2
  11. Next(3
  12. Completed 

Combining

這部分是關於序列的運算,可以將多個序列源進行組合拼裝成一個新的事件序列。

startWith

  1. startWith 會在隊列開始之前插入一個事件元素。 
  2.  
  3. example("startWith") { 
  4.     let subscription = sequenceOf(456
  5.         .startWith(3
  6.         .subscribe { 
  7.             print($0
  8.         } 
  9.  
  10. --- startWith example --- 
  11. Next(3
  12. Next(4
  13. Next(5
  14. Next(6
  15. Completed 
 

combineLatest

如果存在兩條事件隊列,需要同時監聽,那麼每當有新的事件發生的時候,combineLatest 會將每個隊列的最新的一個元素進行合併。

 
  1. example("combineLatest 1") { 
  2.     let intOb1 = PublishSubject<String>() 
  3.     let intOb2 = PublishSubject<Int>() 
  4.  
  5.     combineLatest(intOb1, intOb2) { 
  6.         "\($0) \($1)" 
  7.         } 
  8.         .subscribe { 
  9.             print($0
  10.         } 
  11.  
  12.     intOb1.on(.Next("A")) 
  13.     intOb2.on(.Next(1)) 
  14.     intOb1.on(.Next("B")) 
  15.     intOb2.on(.Next(2)) 
  16.  
  17. --- combineLatest 1 example --- 
  18. Next(A 1
  19. Next(B 1
  20. Next(B 2

zip

  1. zip 人如其名,就是壓縮兩條隊列用的,不過它會等到兩個隊列的元素一一對應地湊齊了之後再合併。 
  2.  
  3. example("zip 1") { 
  4.     let intOb1 = PublishSubject<String>() 
  5.     let intOb2 = PublishSubject<Int>() 
  6.     zip(intOb1, intOb2) { 
  7.         "\($0) \($1)" 
  8.         } 
  9.         .subscribe { 
  10.             print($0
  11.         } 
  12.     intOb1.on(.Next("A")) 
  13.     intOb2.on(.Next(1)) 
  14.     intOb1.on(.Next("B")) 
  15.     intOb1.on(.Next("C")) 
  16.     intOb2.on(.Next(2)) 
  17.  
  18. --- zip 1 example --- 
  19. Next(A 1
  20. Next(B 2
 

marge

merge 就是 merge 啦,把兩個隊列按照順序組合在一起。

  1. example("merge 1") { 
  2.     let subject1 = PublishSubject<Int>() 
  3.     let subject2 = PublishSubject<Int>() 
  4.  
  5.     sequenceOf(subject1, subject2) 
  6.         .merge() 
  7.         .subscribeNext { int in 
  8.             print(int
  9.         } 
  10.  
  11.     subject1.on(.Next(1)) 
  12.     subject1.on(.Next(2)) 
  13.     subject2.on(.Next(3)) 
  14.     subject1.on(.Next(4)) 
  15.     subject2.on(.Next(5)) 
  16.  
  17. --- merge 1 example --- 
  18. 1 
  19. 2 
  20. 3 
  21. 4 
  22. 5 

switch

當你的事件序列是一個事件序列的序列 (Observable<Observable<T>>) 的時候,(可以理解成二維序列?),可以使用 switch 將序列的序列平鋪成一維,並且在出現新的序列的時候,自動切換到最新的那個序列上。和 merge 相似的是,它也是起到了將多個序列『拍平』成一條序列的作用。

  1. example("switchLatest") { 
  2.     let var1 = Variable(0
  3.  
  4.     let var2 = Variable(200
  5.  
  6.     // var3 is like an Observable<Observable<Int>> 
  7.     let var3 = Variable(var1) 
  8.  
  9.     let d = var3 
  10.         .switchLatest() 
  11.         .subscribe { 
  12.             print($0
  13.         } 
  14.  
  15.     var1.value = 1 
  16.     var1.value = 2 
  17.     var1.value = 3 
  18.     var1.value = 4 
  19.  
  20.     var3.value = var2 
  21.     var2.value = 201 
  22.     var1.value = 5 
  23.  
  24.     var3.value = var1 
  25.     var2.value = 202 
  26.     var1.value = 6 
  27.  
  28. --- switchLatest example --- 
  29. Next(0
  30. Next(1
  31. Next(2
  32. Next(3
  33. Next(4
  34. Next(200
  35. Next(201
  36. Next(5
  37. Next(6

注意,雖然都是『拍平』,但是和 flatmap 是不同的, flatmap 是將一條序列變成另一條序列,而這變換過程會讓維度變高,所以需要『拍平』,而 switch 是將本來二維的序列(序列的序列)拍平成了一維的序列。

Error Handling

在事件序列中,遇到異常也是很正常的事情,有以下幾種處理異常的手段。

catchError

catchError 可以捕獲異常事件,並且在後面無縫接上另一段事件序列,絲毫沒有異常的痕跡。

  1. example("catchError 1") { 
  2.     let sequenceThatFails = PublishSubject<Int>() 
  3.     let recoverySequence = sequenceOf(100200
  4.  
  5.     sequenceThatFails 
  6.         .catchError { error in 
  7.             return recoverySequence 
  8.         } 
  9.         .subscribe { 
  10.             print($0
  11.         } 
  12.  
  13.     sequenceThatFails.on(.Next(1)) 
  14.     sequenceThatFails.on(.Next(2)) 
  15.     sequenceThatFails.on(.Error(NSError(domain: "Test", code: 0, userInfo: nil))) 
  16.  
  17. --- catchError 1 example --- 
  18. Next(1
  19. Next(2
  20. Next(100
  21. Next(200
  22. Completed 

retry

retry 顧名思義,就是在出現異常的時候會再去從頭訂閱事件序列,妄圖通過『從頭再來』解決異常。

  1. example("retry") { 
  2.     var count = 1 // bad practice, only for example purposes 
  3.     let funnyLookingSequence: Observable<Int> = create { observer in 
  4.         let error = NSError(domain: "Test", code: 0, userInfo: nil) 
  5.         observer.on(.Next(0)) 
  6.         observer.on(.Next(1)) 
  7.         if count < 2 { 
  8.             observer.on(.Error(error)) 
  9.             count++ 
  10.         } 
  11.         observer.on(.Next(2)) 
  12.         observer.on(.Completed) 
  13.  
  14.         return NopDisposable.instance 
  15.     } 
  16.  
  17.     funnyLookingSequence 
  18.         .retry() 
  19.         .subscribe { 
  20.             print($0
  21.         } 
  22.  
  23. --- retry example --- 
  24. Next(0
  25. Next(1
  26. Next(0
  27. Next(1
  28. Next(2
  29. Completed 

Utility

這裏列舉了針對事件序列的一些方法。

subscribe

subscribe 在前面已經接觸過了,有新的事件就會觸發。

  1. example"subscribe") { 
  2.     let sequenceOfInts = PublishSubject<Int>() 
  3.  
  4.     sequenceOfInts 
  5.         .subscribe { 
  6.             print($0) 
  7.         } 
  8.  
  9.     sequenceOfInts.on(.Next(1)) 
  10.     sequenceOfInts.on(.Completed) 
  11.  
  12. --- subscribe example --- 
  13. Next(1) 
  14. Completed 
  15.  
  16. subscribeNext 
  17.  
  18. subscribeNext 也是訂閱,但是隻訂閱 .Next 事件。 
  19.  
  20. example("subscribeNext") { 
  21.     let sequenceOfInts = PublishSubject<Int>() 
  22.  
  23.     sequenceOfInts 
  24.         .subscribeNext { 
  25.             print($0) 
  26.         } 
  27.  
  28.     sequenceOfInts.on(.Next(1)) 
  29.     sequenceOfInts.on(.Completed) 
  30.  
  31. --- subscribeNext example --- 
 

subscribeCompleted

  1. subscribeCompleted 是隻訂閱 .Completed 完成事件。 
  2.  
  3. example("subscribeCompleted") { 
  4.     let sequenceOfInts = PublishSubject<Int>() 
  5.  
  6.     sequenceOfInts 
  7.         .subscribeCompleted { 
  8.             print("It's completed"
  9.         } 
  10.  
  11.     sequenceOfInts.on(.Next(1)) 
  12.     sequenceOfInts.on(.Completed) 
  13.  
  14. --- subscribeCompleted example --- 
  15. It's completed 

subscribeError

  1. subscribeError 只訂閱 .Error 失敗事件。 
  2.  
  3. example("subscribeError") { 
  4.     let sequenceOfInts = PublishSubject<Int>() 
  5.  
  6.     sequenceOfInts 
  7.         .subscribeError { error in 
  8.             print(error) 
  9.         } 
  10.  
  11.     sequenceOfInts.on(.Next(1)) 
  12.     sequenceOfInts.on(.Error(NSError(domain: "Examples", code: -1, userInfo: nil))) 
  13.  
  14. --- subscribeError example --- 
  15. Error Domain=Examples Code=-1 "The operation couldn’t be completed. (Examples error -1.)" 
 

doOn

  1. doOn 可以監聽事件,並且在事件發生之前調用。 
  2.  
  3. example("doOn") { 
  4.     let sequenceOfInts = PublishSubject<Int>() 
  5.  
  6.     sequenceOfInts 
  7.         .doOn { 
  8.             print("Intercepted event \($0)"
  9.         } 
  10.         .subscribe { 
  11.             print($0
  12.         } 
  13.  
  14.     sequenceOfInts.on(.Next(1)) 
  15.     sequenceOfInts.on(.Completed) 
  16.  
  17. --- doOn example --- 
  18. Intercepted event Next(1
  19. Next(1
  20. Intercepted event Completed 
  21. Completed 
 

Conditional

我們可以對多個事件序列做一些複雜的邏輯判斷。

takeUntil

takeUntil 其實就是 take ,它會在終於等到那個事件之後觸發 .Completed 事件。

 
  1. example("takeUntil") { 
  2.     let originalSequence = PublishSubject<Int>() 
  3.     let whenThisSendsNextWorldStops = PublishSubject<Int>() 
  4.  
  5.     originalSequence 
  6.         .takeUntil(whenThisSendsNextWorldStops) 
  7.         .subscribe { 
  8.             print($0
  9.         } 
  10.  
  11.     originalSequence.on(.Next(1)) 
  12.     originalSequence.on(.Next(2)) 
  13.  
  14.     whenThisSendsNextWorldStops.on(.Next(1)) 
  15.  
  16.     originalSequence.on(.Next(3)) 
  17.  
  18. --- takeUntil example --- 
  19. Next(1
  20. Next(2
  21. Completed 

takeWhile

takeWhile 則是可以通過狀態語句判斷是否繼續 take 。

 
  1. example("takeWhile") { 
  2.     let sequence = PublishSubject<Int>() 
  3.     sequence 
  4.         .takeWhile { int in 
  5.             int < 2 
  6.         } 
  7.         .subscribe { 
  8.             print($0
  9.         } 
  10.     sequence.on(.Next(1)) 
  11.     sequence.on(.Next(2)) 
  12.     sequence.on(.Next(3)) 
  13.  
  14. --- takeWhile example --- 
  15. Next(1
  16. Completed 

Aggregate

我們可以對事件序列做一些集合運算。

concat

concat 可以把多個事件序列合併起來。

 
  1. example("concat") { 
  2.     let var1 = BehaviorSubject(value: 0
  3.     let var2 = BehaviorSubject(value: 200
  4.  
  5.     // var3 is like an Observable<Observable<Int>> 
  6.     let var3 = BehaviorSubject(value: var1) 
  7.  
  8.     let d = var3 
  9.         .concat() 
  10.         .subscribe { 
  11.             print($0
  12.         } 
  13.  
  14.     var1.on(.Next(1)) 
  15.     var1.on(.Next(2)) 
  16.  
  17.     var3.on(.Next(var2)) 
  18.  
  19.     var2.on(.Next(201)) 
  20.  
  21.     var1.on(.Next(3)) 
  22.     var1.on(.Completed) 
  23.  
  24.     var2.on(.Next(202)) 
  25.  
  26. --- concat example --- 
  27. Next(0
  28. Next(1
  29. Next(2
  30. Next(3
  31. Next(201
  32. Next(202

reduce

這裏的 reduce 和 CollectionType 中的 reduce 是一個意思,都是指通過對一系列數據的運算最後生成一個結果。

  1. example("reduce") { 
  2.     sequenceOf(0123456789
  3.         .reduce(0, +) 
  4.         .subscribe { 
  5.             print($0
  6.         } 
  7.  
  8. --- reduce example --- 
  9. Next(45
  10. Completed 

Next

基礎入門大概就是這些了,有了前面 《Functional Reactive Programming in Swift - Part 1》 的鋪墊,似乎理解起來十分愉快,不過還是不夠深入,在下一章會在具體項目中操練起來。

操練起來!跑個操場吧少年!

Run the playground in your Xcode!


參考文獻:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章