RxSwift給Swift帶來了原生Reactive編程的功能
RxSwift 項目以將 Rx 編程模型應用至Swift中為目標,其中包含了盡可能多的抽象概念。InfoQ采訪了項目的維護者Krunoslav Zaher。
RxSwift是基于 Observable<Element> 接口的,這個接口旨在能夠執行異步運算和事件流的簡單組合。在RxSwift中,觀察者和序列相同,所以可以通過 Observable 接口中的操作模仿在序列元素上的高階操作,例如數據或事件流。
RxSwift中靈活的編程模型使 許多不同的用例 成為可能:綁定,包括UI綁定;重操作;代理;KVO;通知。
接下來的這個例子展示了你如何通過 rx_text 操作綁定兩個文本域。其中一個的值和另一個的值通過一個異步API( WolframAlphaIsPrime )關聯起來。無論前一個值何時改變,后一個的值都會通過一個異步調用來更新:
let subscription : Disposable = primeTextField.rx_text // type is Observable
.map { WolframAlphaIsPrime($0.toInt() ?? 0) } // type is Observable
> .concat() // type is Observable
.map { "number \($0.n) is prime? \($0.isPrime)" } // type is Observable
.bindTo(resultLabel.rx_text) // return Disposable that can be used to unbind everything // This will set resultLabel.text to "number 43 is prime? true" after // server call completes. primeTextField.text = "43" // ... // to unbind everything, just call subscription.dispose()
InfoQ采訪了項目的維護者Krunoslav Zaher。
你可以解釋一下Rx編程需要什么樣的觀念轉變嗎?
這都取決于你的編程背景是什么。對于那些大部分工作經驗都是使用ObjectiveC或Swift(對,也包括Swift)進行編程的人,我會說這需要他們不把它看作一種編程,而是看作一個動態系統的行為聲明。
當一個人使用可觀察的序列并使用操作來轉化它們,事實上,他/她是在定義可觀察序列的結果如何與那些操作應用的源序列相關聯。這可能在剛開始的時候看起來很奇怪。而真正重要的是將它們看作可觀察的序列。
使用不一樣的、不太準確的方式思考可觀察的序列會帶來很多問題(流、信號、導管等)。那些東西有時候可以用來幫助新手探索Rx,但是如果使用的時間過長,它們只會在接下來的開發中帶來很多困惑。人們有時候使用它們是因為Rx可以用在模擬系統的多狀態部分,但是那只是故事的一部分,而我建議大家不要那樣思考。
使用那些項(流、信號、導管等)思考的問題在于它們帶有一個隱含假定:
定義 Observable 時帶有共享的值,并且可以從外部設定的當前值也是一樣的。而 Observable 會被莫名其妙地直接取消,這看起來像future或promise。
而事實上:
Observable 只是一個如何計算序列的定義。沒有計算會在序列定義后(
let result =
source.map(transformObservableSequence)
)自動地執行。這和 Swift 中的 SequenceSequence 是一樣的。當綁定一個觀察者時(這與調用SequenceType中的generate方法相同)才會執行計算,并且可以通過處理 Disposable 對象的結果來取消特定的計算。 Observable 當然可以代表多狀態的計算,它們共享潛在的綁定并 source 可觀察的序列(使用 shareReplay(1) 操作等),但是這不是默認的行為。
我認為部分的問題在于也許人們一直在使用future、promise或其他更簡單的、使用方式相似的reactive庫,所以他們自然地認為Rx在其他的情況下也是同樣的表現,而這對于新手來說顯然是令人困惑的。
奇怪的是那些單方面的屬性對剛開始使用Rx的人們造成了很大的問題,有時候門檻會變得太高以至于人們變的沒有動力,但是從另一角度來看,這正是我個人認為Rx美的原因。
它美的地方在于你可以只通過一句話就能教會一個人使用Rx: Observable<T> 代表了元素類型為T的可觀察序列(與 Swift 中的 SequenceSequence 是一樣的),其中每個元素都可以調用 subscribe (和 SequenceSequence 中的 generate 方法相同)方法來注冊自己的接受序列元素的 observer (返回信號)。
如果這方面很清楚的話,所有的其他東西都只是細節,或變得非常明顯和自然。
將Rx看作另一個庫而不是一個不同的概念/抽象,并且開始在StackOverflow或相似的網站上開始查閱它,將會帶來許多問題。在學習Rx時,唯一需要學習的部分就是理解可觀察序列的句子,這樣的話其他的東西就很顯而易見了。這時候,陡峭的學習曲線就消失了。
使用Rx的好處在哪里?
這里有很多的好處,我的描述中可能會跳過許多:
-
你可以停下編程,并且開始著眼于你的程序如何表現,使你的電腦了解如何應對暫態和不能預料的情況。
-
你可以停下重新一遍又一遍地實現同一個模式,并且將它們抽象為可觀察序列的操作。也許這其中最普遍的是:
- retry
- combileLatest(將多個多狀態對象的最新值結合起來,這和Excel或其他電子制表軟件在計算公式時做的工作很類似)
- map(將序列的值轉化并放入另一個序列)
- merge(將多個源的事件結合起來并放入同一個源)
- flatMapLatest(當下一個計算請求到來時,自動地取消之前的異步操作)
- refCount(當你想要下載什么東西并且想確認至少有人需要下載結果時,下載就應該繼續,但是如果沒有人需要下載結果,那么下載就會被自動取消)
- zip(想要創建N個網絡請求,等到所有請求都完成了之后映射它們的結果?這當然可以,輕而易舉)
-
你可以統一所有不同的通知并觀察其中一個的原理,例如:
- 代理
- 通知中心的通知
- KVO
- 目標/行動的模式
-
通過使用Rx你不僅可以將計算結果連起來,還可以更隨意地取消(處理)計算,例如:
- app中有三處下載圖片的請求,如果其中的兩個取消了請求,而依然有人需要那些信息,那么圖片還會繼續下載
- 你需要做很多由異步操作連接起來的復雜的數據轉換,而它們有可能會失敗,一旦使用了結束操作,則所有的東西都會被自動處理。
順便一提,這需要什么成本嗎?
我認為還沒有什么顯著的性能影響,我們真的實在地以性能為中心,并且我認為性能影響可能比人們認為的更少,比我們對其施加的性能測試更多。
我們有一個小型的包含在項目中的性能基準,我們用其來衡量操作的處理器使用率和它們在使用時的分配值,所以測試每個操作或結構的性能都是很容易的。
恕我直言,最大的成本是人們誤用概念/庫的時候。在那樣的情況下,世事難料。那不是概念/庫自己的問題,但是依然是我會考慮的一種潛在成本。不理解怎么使用概念、或錯誤地使用概念都是成本最高的。
如果應用沒有使用單向數據流作為架構,那么僅僅引入Rx而不是適應架構的話也許不會自動地解決任何問題。情況可能還會更糟,因為你現在又多加了一層你不完全理解怎么去使用的架構。另一方面來說,有很多情況下,怎么使用RxSwift是很清晰的。例如網絡層、數據模型的觀察等。所以以有益的方式開始使用Rx并沒有那么難,你可以看它是如何執行的,然后就能慢慢在其之上構建自己的代碼。我們曾經試圖糾正這個錯誤,提供了一些如何使用它的小例子(RxExample項目),但是看起來我嗎依然需要做更多這方面的工作。
人們使用這個庫時面臨的其中一個現實問題是太依賴調用堆棧調試技術。用這樣的方式調試任何reactive庫都不正確。我們試圖通過提供一系列可以用于調試目的和跟蹤系統行為的操作來糾正這個錯誤。
我們還有很多有關reactive框架的工作和應用Rx到一些具體問題的工作需要完成。
你將怎么描述RxSwift的成熟度?你知道有什么項目正在使用它嗎?
我個人一直對使用一些新的閃耀的/銀子彈項目抱有懷疑的態度,所以我也認為人們剛開始會對使用RxSwift抱有懷疑的態度,而且我也是這么期望的。
但是從另一個角度來說,我們所有的事情都是在GitHub上做的并且是完全開放的。
在開源的應用中,我了解到的最有名的也許是Artsy的Eidolon應用。它的生態系統正在與GitHub上的RxSwiftCommunity一起逐步形成。
CocoaPods給我們提供了下載數據和使用某項pod的應用數量。RxSwift ~> 2.0開始變的十分引人注目,所以我對項目的前景很興奮。我們還支持Carthage和Linux上的Swift包管理器,但是我不確定用什么方式能夠提供更精確的使用數據。
RxSwift的未來發展中還包括什么?
在2.0.0版本中我們沒有期待更多的本質性變化。我們也許會加入一些小功能,提升Linux支持等。
當我們開始著手于Swift 3.0編譯器后,我們將會給出更精確的藍圖。總的來說,我們的目標是:
- 類型更安全
- 性能更好
- 功能更少
對,你沒聽錯,我們確實致力于更少的功能,而盡可能將所有的東西都放入我們的整個項目的生態下。我認為現在的RxSwift庫就是我們所期待的規模,但是保持這個規模則非常具有挑戰性。添加新的操作和功能要面臨很大壓力。
這也意味著說服人們不在新的版本中包括一大堆新操作和擴展是好事肯定是非常困難的,并且我也認為人們也會失望,但是為了增加這個項目的可維護性,這確實是我們需要做的。
我認為保持RxSwift的功能將是最難執行的部分。
你在Swift中實現Rx有什么經驗?語言的性能怎么樣?
Swift真的是一個很好的語言,而且它確實是我使用過的最美的語言之一。而另一方面,它還沒有什么明顯能使它十分有用的特性,但是它還是一種很年輕的語言所以我確信這個問題會被解決。
如果你粗略地看,那么Swift看起來像一個C++的簡約、現代的版本,但如果你看一下它的生成代碼,你會驚訝于它生成代碼所需要的執行時間開銷。由于它與ObjectiveC的互通性,有些代碼是必要的,但我們還是希望這樣的問題能被解決。
可以這么說:Swift編譯器依舊是一個學步兒童。我猜測所有的事情都表現得已如期望。
RxSwift嘗試盡可能地與 ReactiveX.io 和它的文檔相一致,它可以通過CocoaPods、Carthage或直接通過GitHub進行 安裝 。
查看英文原文: RxSwift Brings Native Reactive Functional Programming to Swift
來自: http://www.infoq.com/cn/news/2016/04/rxswift-reactive-swift