本文將介紹一個響應式編程架構 RxSwift,并結合使用 Swift 的函數式功能來編寫更簡潔、更表現力的代碼,從而管理應用狀態及并行任務。
Swift 及其函數式功能
Swift 可被認為是一種現代的面向對象語言,對泛型編程有著原生支持。雖然它不是一種函數式語言,但其中的一些特性卻可以讓我們利用函數式方式來編程,比如可以利用閉包、first-class 類型函數,以及不可變的value 類型。
然而,Cocoa Touch 是一個面向對象的架構,有著這一范式所強制的約束。軟件開發中常見的問題在于如何管理共享應用狀態以及異步數據的并行任務。
函數式編程解決這些問題的辦法是,賦予不可變狀態一定的特權,以及將應用邏輯定義為不會在應用生存周期內改變的表達式。通過定義自包含的函數,并行化計算就會變得簡單,最大程度減少并發問題。
響應式模型
響應式編程根源于 FRP(函數響應式編程)命令驅動的編程方式,是以異步數據流的形式進行編程。
這可能有些難懂,所以最好通過一個簡單的例子來大體了解一下。
表達一個變量間關系
假如有 2 個變量(A 和 B),它們的值會在應用運行時中經常改變。還有一個變量(C),它的值取決于前兩個變量值。
2. var B = 20
3. let C = A * 2 + B
4.
5. // 當前值
6. // A = 10, B = 20, C = 40
7.
8. A = 0
9.
10. // 當前值
11. // A = 0, B = 20, C = 40
C 值與 A 和 B 有關,B 只被當 A 和 B 的賦值操作執行后,它們三者之間的關系很快就解散了。這時再改變 A 與 B 的值,將不會對 C 的值有任何影響。
所以,在任何指定時間,要想計算表達式,就必須根據 A 和 B 的當前值,重新指定 C 值,重新計算。
用響應式編程方式該怎么做呢?
采用響應式模式,我們將創建兩個流,來傳遞 A 或 B 值的改變。
一般可使用彈珠圖來展示這個原理。如下圖所示,每一行表示連續的一段時間,每一個彈珠表示發生在特定時刻的一個事件。


Cocoa Touch 中的做法
在 Cocoa Touch 中,使用鍵值對觀察,為發生改變的變量添加觀察者,當 KVO 系統通知時再進行處理。
self.addObserver(self, forKeyPath:”valueA”, options: .New, context: nil)
self.addObserver(self, forKeyPath:”valueB”, options: .New, context: nil)
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
let C = valueA * 2 + valueB
}
如果變量與用戶界面相連,那么可以在 UIKit 中定義一個當觸發變化事件時即被調用的處理器:
sliderA.addTarget(self, action: “update”, forControlEvents: UIControlEvents.ValueChanged)
sliderB.addTarget(self, action: “update”, forControlEvents: UIControlEvents.ValueChanged)
func update() {
let C = sliderA.value * 2 + sliderB.value
}
但是,對于調用的變量、它們的生存周期以及改變它們值的事件,以上兩種方法都沒有定義一種持久、顯式的關系。
我們可以用響應式編程模式來處理這種情況。當前對于 OS X 和 iOS 開發者而言,有多種不同的實現,比如 RxSwift 和 ReactiveCocoa。
下面簡單介紹一下 RxSwift,不過這兩種架構的概念是相似的。
RxSwift
RxSwift 繼承自觀察者模式,模擬 Cocoa Touch 對象中的異步數據流,按通常的集合來看待這些對象。通過利用可觀測流繼承一些 Cocoa Touch 類,可以訂閱它們的輸出,并利用復合運算(如 filter()
、merge()
、map()
和 reduce()
等)來使用這些輸出。
還回到剛才的例子中,假設一個 iOS 應用有兩個滑塊(sliderA 和 sliderB),并希望利用之前的表達式(A * 2 + B
)不斷更新標簽(labelC)的值:
1. combineLatest(sliderA.rx_value, sliderB.rx_value) {
2. $0 * 2 + $1
3. }.map {
4. “Sum of slider values is ($0)”
5. }.bindTo(labelC.rx_text)
利用 UISlider
類的 rx_value 后綴,將滑塊的值屬性轉化為可觀測類型,
通過在每個滑塊的可觀測類型上使用 combineLatest()
操作,我們還創建了一種新的可觀測類型,只要其中任何一個源流釋放出一個項目,它就會釋放項目。結果就是一個元組,每個滑塊值都可以通過操作回調而轉換(代碼行 2)。然后將變換值映射到信息性字符串(代碼行 4),并將其值綁定到標簽上(代碼行 5)。
通過組合 3 個獨立的操作(combineLatest()
、map()
、bindTo()
),我們就能精確地表達三種對象之間的關系并不斷更新應用的 UI,響應應用狀態中的改變。


額外介紹
上面的內容只是對 RxSwift 用途做了一個粗淺的介紹。
參看樣例代碼,在這個例子中,使用可鏈接的異步任務下載在線資源。如果這篇文章引發了你的好奇心,一定要看看這個例子。
然后,可以讀讀這篇文檔,學習其他一些 API 擴展,采用一種函數式并具有表現力的方式來開發 iOS 應用。
還可閱讀 使用輕量級模式 來了解Swift 模式如何幫助你處理大量相似對象。
作者簡介
Milton Moura(@mgcm)是一位葡萄牙的自由 iOS 開發者。他曾就職于涉及航空、電信、能源等領域的多家公司,如今全心致力于使用蘋果技術開發優秀應用。除了醉心于設計與用戶交互外,他還非常喜歡新的軟件開發方式。
版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。