ReactiveCocoa 4 官方文件翻譯
我翻譯的RAC4的文件
ReactiveCocoa 4 官方文件翻譯
ReactiveCocoa 4 文件翻譯:基本操作符(一)
ReactiveCocoa 4 文件翻譯:基本操作符(二)
ReactiveCocoa 4 文件翻譯:框架組成介紹
ReactiveCocoa 4 文件翻譯:相容Objective-C
ReactiveCocoa 4 文件翻譯--設計指南(一):事件的規範
ReactiveCocoa 4 文件翻譯:設計指南(二):訊號的規範
[翻譯]ReactiveCocoa 4 最佳實踐
ReactiveCocoa (RAC) 是一個Cocoa框架,受Functional Reactive Programming啟發。它提供Api合成變換(composing and transforming)隨著時間改變的資料流。
相容性
關於 RAC 4的文件是在Swift 2.1.x下使用。對於Swift 1.2的支援請看 RAC 3.
介紹
ReactiveCocoa來源於functional reactive programming(Input and Output)。
區別於使用不斷變化修改的變數,RAC提供了“事件流”,通過 Signal 和 SignalProducer 型別來表示, 它們隨著時間傳送值。
事件流統一了Cocoa用於事件和非同步處理的常用模式,包括:
- 委託方法
- 回撥blocks
- 通知
- 控制元件的actions和響應事件鏈
- Futures and promises
- Key-value observing (KVO)
因為這些不同的機制能夠用一種相同的方式處理,可以很容易的宣告成鏈(chain)並且把它們聯合在一起,用更少的程式碼和狀態連線它們。
更多關於RAC裡的概念可以檢視Framework Overview.
例子:線上搜尋
假設你有一個text field,每當使用者輸入文字時,你都會發起一個網路請求根據輸入的關鍵字查詢。
實時觀察文字變化
實現這個目的的第一步,使用RAC中UITextField的一個擴充套件方法:
<pre><code>
let searchStrings = textField.rac_textSignal()
.toSignalProducer()
.map { text in text as! String }
</code></pre>
這樣產生了一個signal producer 來傳送輸入的字串。 ( text as! String這種型別對映在當前是必需的,為了從OC橋接當前的擴充套件方法
傳送網路請求
獲得了每次輸入的字串,我們想要傳送一個網路請求。RAC也為我們提供了NSURLSession的一個擴充套件方法來實現:
<pre><code> let searchResults = searchStrings
.flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in
let URLRequest = self.searchRequestWithEscapedQuery(query)
return NSURLSession.sharedSession().rac_dataWithRequest(URLRequest)
}
.map { (data, URLResponse) -> String in
let string = String(data: data, encoding: NSUTF8StringEncoding)!
return self.parseJSONResultsFromString(string)
}
.observeOn(UIScheduler())
</code></pre>
這段程式碼將字串的producer轉換成了一組包含了搜尋結果的producer,並且會在主執行緒中處理(由於UIScheduler的作用).。
另外這裡的flatMap(.Latest)確保只有最後的一次搜尋會被執行。
如果當一個請求還在處理中,此時使用者輸入新的字元,在發起新的請求之前會取消之前的請求。想想這些如果自己實現的需要寫多少程式碼!
接收結果
這樣實際上還沒有執行,因為producers必須started後才執行(對於返回結果沒有被使用時做的優化)。這個很簡單:
<pre><code>searchResults.startWithNext {
results in print("Search results: (results)")
}
</code></pre>
我們獲取值用於<code>Next</code>中的event:包含了請求結果,並且把他們log到了控制檯。這裡也可以寫其他UI控制的程式碼,比如reload一個table view。
失敗處理
到目前為止,這個例子中,任何的網路錯誤都會產生一個<code>Failed</code> event,這會導致整個事件流終止。不幸的是,這意味著之後請求不會被髮起。
為了避免這樣的情況,我們需要決定當失敗發生時怎樣處理。最快速的解決方案就是記錄它們,然後忽略它們:
<pre><code>.flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in
let URLRequest = self.searchRequestWithEscapedQuery(query)
return NSURLSession.sharedSession()
.rac_dataWithRequest(URLRequest)
.flatMapError { error in
print("Network error occurred: (error)")
return SignalProducer.empty
}
}
</code></pre>
通過將失敗替換為空事件流,可以有效的忽略它們。
然而,在放棄前最好重試幾次。在一次,使用retry可以方便的達到這個目的。
改進後的searchResults producer會像這樣:
<pre><code>
let searchResults = searchStrings
.flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in
let URLRequest = self.searchRequestWithEscapedQuery(query)
return NSURLSession.sharedSession()
.rac_dataWithRequest(URLRequest)
.retry(2)
.flatMapError { error in
print("Network error occurred: (error)")
return SignalProducer.empty } }
.map { (data, URLResponse) -> String in
let string = String(data: data, encoding: NSUTF8StringEncoding)!
return self.parseJSONResultsFromString(string) }
.observeOn(UIScheduler())
</code></pre>
降低請求頻率
現在,我們假設你只希望在使用者輸入暫停時才發起請求以減少網路請求。
RAC通過<code>throttle</code>操作符可以用於實現這個需求:
<pre><code>
let searchStrings = textField.rac_textSignal()
.toSignalProducer()
.map { text in text as! String }
.throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)
</code></pre>
這樣當間隔小於0.5秒時值不會被髮送出去,意味著使用者必須停止編輯0.5秒後我們才會使用輸入的字串去搜尋。
如果用自己實現這個功能,真是要寫不少程式碼,而且還會影響程式碼的可讀性。但是在RAC中,只需要一個操作符就可以方便將時間控制加入事件流。
Objective-C 和 Swift
雖然RAC是作為一個OC的框架開始的,但是從 版本3.0開始,所有的主要特性開發都是基於 Swift API。
RAC的Objective-C API和Swift API是完全分開的,但是有一個bridge可以將他們互相轉換。這主要是為了相容使用RAC的一些老專案,或者用於一些還沒有被加入Swfit API的一些Cocoa擴充套件。
Objective-C API將繼續存在,在可預計的未來將提供支援,但是不會有新的改進。關於使用這些API的資訊可以參考:legacy documentation。
我們強烈建議所有的新專案採用Swift API。
ReactiveCocoa和Rx的關係
ReactiveCocoa 受了 Microsoft’s Reactive Extensions (Rx)庫的不少影響。有很多對於Rx的實現,包括 RxSwift,但是ReactiveCocoa無意於成為Rx的一個實現子集。
RAC和 Rx的區別,主要有以下一些:
- 更簡潔的API
- 解決了令人困惑的常見問題
- 更貼近Cocoa的程式設計習慣
命名
在大部分Rx的版本中,流被稱為Observables,對應於.NET中的<code>Enumerable</code>型別。
另外, Rx.NET大部分的操作符參考了 LINQ,而LINQ是用於操作傳統關係型資料庫的,比如<code> Select </code>和<code> Where </code>。
RAC則最關注於匹配Swift的命名規範, 使用 <code> map </code> 和<code> filter </code>來替換select和where。其他的一些命名來源於Haskell或Elm(使用“signal”的始祖)。
Signals and Signal Producers (“hot” and “cold” observables)
Rx中的“hot”, “cold”, and “warm” observables (對應RAC中的事件流)很容易讓人困惑。
對於這個部分和Typed errors的區別,因為在我翻譯的iOS響應式程式設計:ReactiveCocoa vs RxSwift 選誰好中有更詳細的對比說明,這裡就不翻譯了。
Typed errors
處理錯誤時方式
UI程式設計
很多人不知道Rx怎麼用。即使用Rx進行UI的程式設計很常見,它有幾個特性用於一些特別的場景。
RAC從ReactiveUI借鑑了很多,包括 Actions的基礎操作。
不像ReactiveUI不能直接將Rx改變的對於UI程式設計更友好,為了這個目的則進行了很多次的改動—即使這意味著和Rx的區別越來越大.
歡迎關注我的微博:@沒故事的卓同學
相關文章
- docker官方文件翻譯4Docker
- Moya官方文件翻譯
- docker官方文件翻譯3Docker
- rabbitmq 官方文件翻譯-2MQ
- docker官方文件翻譯5Docker
- docker官方文件翻譯2Docker
- docker官方文件翻譯1Docker
- Core Foundation 官方文件翻譯
- HTTPie 官方文件中文翻譯版HTTP
- BBNorm官方指導文件翻譯ORM
- [翻譯]ElasticSearch官方文件-簡介Elasticsearch
- Redis-py官方文件翻譯Redis
- Akka官方文件翻譯:Cluster Specification
- Python heapq模組官方文件翻譯Python
- ExoPlayer的使用與解析(官方文件翻譯)
- [翻譯]ElasticSearch官方文件-資料的修改Elasticsearch
- Matlab最新的官方文件中文翻譯Matlab
- [翻譯]ElasticSearch官方文件-查詢語言Elasticsearch
- 【Tomcat 6.0官方文件翻譯】—— 簡介Tomcat
- 歡迎參與 KubeVela 官方文件翻譯活動
- kotlinx協程官方文件中文翻譯版本Kotlin
- Kotlin 官方參考文件翻譯完畢Kotlin
- voltDB官方文件第三章翻譯
- PendingIntent 是個啥?官方文件描述的很到位。我給翻譯翻譯Intent
- 文件翻譯器怎麼用?如何翻譯Word文件?
- logback官方文件中文翻譯第七章:FiltersFilter
- Retrofit 2 0非常簡單的入門(翻譯官方文件)
- Detectron2-寫模型(Write Models)官方文件中文翻譯模型
- Dapr 官方文件中文翻譯 v1.5 版本正式釋出
- ElasticSearch入門 官方文件翻譯 - 2.Exploring Your ClusterElasticsearch
- [翻譯]ElasticSearch官方文件-執行查詢和過濾操作Elasticsearch
- django1.8官方文件翻譯:8-5加密簽名Django加密
- ZooKeeper 官方教程[翻譯]
- [翻譯]CMAKE官方教程
- JavaPoet 文件翻譯Java
- [譯]記一次Kotlin官方文件翻譯的PR(內聯類)Kotlin
- RxJava常用操作符官方文件翻譯及Kotlin示例(1)RxJavaKotlin
- 別開心太早,Python 官方文件的翻譯差遠了Python