在 iOS 開發過程當中,咱們幾乎無時無刻都要面對異步事件的處理。例如,按鍵點擊、數據保存、、音頻後臺播放、交互動畫展現。這些事件並不具有特定時序性,甚至它們可能同時發生。html
雖然 Apple 提供了通知、代理、GCD、閉包等異步機制,可是這些機制缺少一個統一的抽象表述。另外,這些機制在處理共享的可變數據或狀態時不夠清晰簡練。固然,這並非說編寫優雅的異步代碼不現實。畢竟與其餘平臺相比 iOS 的異步機制仍是很強大的。git
幸運的是,咱們可以經過 RxSwift 優雅的處理異步代碼。github
至於 RxSwift 的優點以及爲何要使用它,詳見文檔。這裏就不廢話了。編程
其實響應式編程並非一個什麼新的概念,只不過是最近幾年受到了開發者更多的關注。它最先由巨硬提出,主要的目的是爲了應對複雜的 UI 異步事件和應用實時響應。社區中也已經有了各類語言版本的響應式編程實現,包括:RxJS、RxKotlin、Rx.NET、RxScala、RxSwift。這些類庫僅僅只是實現方式存在差別,因此開發者在討論應用邏輯時不會存在溝通障礙。swift
RxSwift 做爲 Swift 語言的響應式編程實現,它在傳統的命令式編程和純函數式編程中找到了一個很好的平衡點。經過使用不可變代碼定義異步處理輸入,RxSwift 以一種肯定可組合的形式對事件作出響應。bash
總的來講,RxSwift 有三個主要構成部分:Observable、Operator、Scheduler 。下面咱們就來一一介紹。服務器
Observable
其中 Observable
對於一個可觀察的整型變量來講,異步環境下它所觸發的事件能夠在時間線上被描繪成這樣一個事件序列:架構
另外,咱們能夠對這三類事件進行組合從而實現更爲複雜的業務邏輯。與此同時,咱們還可使用該機制輕鬆實現代碼解耦和多個對象間數據傳遞,無需編寫代理或者閉包代碼。
這裏,咱們還有一點值得注意。那就是可觀察序列其實有兩種類型。
該序列是指那些最後會以 completed 或者 error 事件終極生命週期的可觀察對象。最典型的例子就是,經過 API 進行網絡請求:
下面是一個文件下載請求的 Rx 範式的代碼:
API.download(file: "http://www...")
.subscribe( onNext: { data in
append data to temporary file },
onError: { error in
display error to user },
onCompleted: {
use downloaded file })複製代碼
這段代碼中 API.download (file:) 函數會建立一個 Observable 實例對象,而且在整個數據接收過程當中會不斷的觸發 next 事件。而後,咱們在 next 事件中會將這些片斷數據保存到臨時文件中。若是此過程出現錯誤的話,咱們會將錯誤信息展現給用戶。若是一切順利咱們會將臨時文件保存到設備中。最後在下載完成後,咱們能夠在 completed 進行下一步的邏輯處理。
與網絡任務不一樣的是,UI 以及交互事件是無限觀察序列。它們並不存在一個明確的生命週期終結點。例如,針對可能的設備方向旋轉,咱們須要實時進行佈局修改。而設備的方向旋轉自己是隨機發生的而且與應用自己具備一樣的生命週期。所以 Rx 也須要一種機制支持這種無限觀察序列。
針對這種狀況,在 RxSwift 中咱們能夠經過如下代碼來應對:
UIDevice.rx.orientation.subscribe(onNext: { current in
switch current {
case .landscape:
re-arrange UI for landscape
case .portrait:
re-arrange UI for portrait
}
})複製代碼
ObservableType 以及 Observable 類的實現中都包含大量的異步處理方法,這些方法也被稱爲操做符。因爲這些操做符只是進行異步輸入處理併產生對應輸出,因此它並不會對應用產生多餘的反作用。另外,由於操做符之間的高度解耦因此咱們很容易對它進行組合以期實現複雜的功能。
例如,對於上面的設備方向旋轉,咱們能夠對全部的狀況進行過濾而後對部分值進行進一步處理。
UIDevice.rx.orientation
.filter { value in
return value != .landscape
}
.map { _ in
return "Portrait is the best!"
}
.subscribe( onNext: { string in
showAlert(text: string)
})複製代碼
上面的代碼中,咱們首先會將全部 .landscape 方向過濾掉不作任何處理。而後,咱們再將剩下的 portrait 轉化爲字符串 Portrait is the best! 。整個處理流程大體以下:
這種函數式的操做符讓咱們能夠靈活的組合出更強大的功能。
Schedulers 是一個與 GCD 相對應的概念,只不過前者使用起來更爲方便。RxSwift 中預約義的 Schedulers 足夠開發者應對絕大多數的編程場景。
例如,咱們可使用串型序列 SerialDispatchQueueScheduler 來處理 next 事件,經過 ConcurrentDispatchQueueScheduler 運行並行文件下載任務,經過 OperationQueueScheduler 運行一個 NSOperationQueue 操做隊列。甚至你能夠在同一個觀察對象的不一樣任務中使用不一樣的 Schedulers 類型,以下圖:
咱們將左側的任務用不一樣的顏色加以區分,而後在右側任務被拆分爲不一樣的步驟而且放在不一樣 Schedulers 中。例如,network subscription 任務就被拆分爲三個步驟並依次放入了 Custom NSOperation Scheduler 、Background Concurrent Scheduler、Main Thred Serial Scheduler 。
值得注意的是, RxSwift 並無對客戶端的應用架構做出硬性規定。這意味着,咱們能夠在已有項目中引入 RxSwift 進行響應式編程實踐。固然已有框架中一定存在一個最適合 RxSwift 的,而它就是 MVVM。由於在 MVVM 中咱們能夠將 VM 中的部分屬性直接與 UI 進行綁定。
另外,對於 iOS 編程來講僅僅有 RxSwift 是遠遠不夠的。RxSwift 只是 Swift 語言的響應式實現,咱們還須要一種 Cocoa 層面的實現。好在這裏存在 RxCocoa 做爲 UIKit 的響應式補充。前面設備方向代碼 UIDevice.rx.orientation 就是 RxCocoa 的應用 。
做爲系列開篇,本文介紹了 RxSwift 的一些基本理念和構成,更多相關的內容將會在後面帶來。
原文地址