ReactiveCocoa簡介翻譯

> 做爲一個iOS開發小魚,一直對RAC的使用垂涎不已,卻一直沒能深刻學習,在項目閒暇的空檔自娛自樂作個官方簡介的中文翻譯(結合google翻譯).能力有限,若有謬誤,還望指正海涵.如下爲正文html

ReactiveCocoa

框架代碼地址:[https://github.com/ReactiveCocoa/ReactiveCocoa][1]

ReactiveCocoa(RAC)是一個Cocoa框架,靈感來自於函數響應式編程。它提供了實時地對數據流steams of values變化進行展現和響應的API。react

目錄:

  1. 介紹git

  2. 示例:即時網絡搜索github

  3. Objective-C和Swift的支持狀況編程

  4. RAC與Rx之間的關係數組

  5. 使用方法promise

  6. 操做步驟網絡

若是你已經熟悉了函數響應式編程或基本瞭解了ReactiveCocoa,能夠去文檔文件夾裏瞭解它的運行原理等信息。或者,直接進入咱們的文檔評論區,瞭解更多的相關API。app

若是您有什麼疑問,請先查看該問題在問題討論區StackOverflow上是否已經有了相關的討論.若是沒有的話,可隨時提交給咱們!框架

兼容性

這份RAC4文檔適用於Swift 2.2.x. 關於Swift 1.2的支持請看RAC3.

介紹

ReactiveCocoa的靈感來自於函數響應式編程.

不一樣於就地即時地替換和修改可變變量的方案, RAC提供了「事件流」方案, 經過信號Signal和信號產生器的SignalProducer形式來展現和響應實時的數據值values的變化.

"事件流"統一了Cocoa裏全部的非即時的事件處理模式,包括了:

  • 代理方法 Delegate methods

  • block回調 Callback blocks

  • 通知模式 NSNotifications

  • 控制動做和響應鏈事件 Control actions and responder chain events

  • 觀察者模式 Key-value observing (KVO)

  • Futures and promises (不瞭解)

因爲全部這些不一樣的機制能夠經過相同的方式展現,容易發現將它們整合連接在一塊兒,可使代碼更精簡高效,同時使項目統一性更高.less spaghetti code and state to bridge the gap

更多的有關ReactiveCocoa概念信息,請參見框架概述

實例:在線搜索,即時響應

比方說,你有一個文本輸入框,當用戶鍵入字段,你想即時對其進行搜索查詢。

監控文本編輯

第一步是監控文本輸入框的字段編輯狀況, 專門對UITextField使用RAC擴展以實現這個需求:

let searchStrings = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }

以上代碼給咱們提供了一個可以發送字符串類型的值的信號產生器. (從Objective-C橋接擴展方法是至關必要的).

創建網絡請求

咱們須要隨着字符串改變而同時執行網絡請求. 同時, RAC提供的一個叫作NSURLSession的擴展能夠知足這個需求:

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())

這個將在主線程上將咱們的字符串產生器轉換成一個包含搜索結果的數組的產生器.(感謝UIScheduler).
此外,flatMap(.Latest) 確保了只有最後一個搜索操做能被執行.

若是用戶在執行網絡請求時候輸入了其餘的字節, 那麼該網絡請求將在下一個網絡請求開始前被取消.

試想若是要本身寫, 須要多少代碼才能實現這個效果.

接收結果

這不會立刻真正地執行, 由於若是要收取搜索結果,那麼信號產生器必須先運行(這樣能夠防止無效運行).這很容易作到:

searchResults.startWithNext { results in
    print("Search results: \(results)")
}

這樣, 咱們要作的就是等待包含搜索結果的事件,而後將事件裏的搜索結果打印到控制檯,而這個打印操做能夠很簡單地用其餘操做替代,好比說刷新屏幕上顯示的各類視圖.

故障處理

這個例子寫到這一步,隨便一個網絡故障都有可能終止事件流.甚至可能會致使全部將來的查詢操做都不會進行.

對此,咱們須要決定當故障發生時應該如何處理.最快的解決辦法就是先記錄故障,而後忽略他們.

.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
        }
    }

咱們能夠用一個頗有效的故障忽略辦法,就是:經過用空事件流替換故障.

但在放棄以前多作幾回嘗試會更合適一些,並且有一個很方便的重試操做正對應這個需求.

咱們的改進後的搜索結果產生器能夠是這樣的:

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())

減小網絡請求的流量消耗

能夠經過按期地執行實際的搜索操做, 以減小流量.

ReactiveCocoa裏有一個咱們能應用於搜索的操做:節流器throttle:

let searchStrings = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }
    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)

這能夠防止程序發送時間間隔少於0.5秒的數據請求.

若是要本身實現這個效果將會須要簽名驗證的狀態significant state, 並且代碼也會更加難以閱讀! 但經過ReactiveCocoa, 咱們只須要導入一個時間到咱們的事件流裏.

調試事件流

因爲其自己的特性,一個流的堆棧可能有大量的構架, 其中大多一般可使調試成爲一件使人難搞的事情. 以下的插入附加做用side effect到流是一個比較基礎的調試方法:

let searchString = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }
    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)
    .on(event: { print ($0) }) // the side effect

而如下操做將打印出這個流的事件, 同時不影響這個流的本來行爲.信號產生器SignalProducer和信號*Signal都會自動爲你運行打印操做:

let searchString = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }
    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)
    .logEvents()

更多信息和進階操做,請查看調試技術文檔.

Objective-C 和 Swift

雖然ReactiveCocoa最開始是一個基於Objective-C的框架, 可是從3.0版本開始,全部的主要功能開發都集中在Swift的API上.

在RAC裏,Objective-C的API和Swift的API是徹底分開的, 可是兩者的轉換是能夠橋接的.這主要是爲了兼容老的舊的ReactiveCocoa項目, 或者是使用了還沒添加到Swift API 的Cocoa擴展的項目.

目前來講,Objective-C的API將繼續存在而且獲得支持,但不會獲得不少的改進. 更多有關於API使用的信息,請查詢咱們的詳細文檔.

咱們強烈建議全部新項目使用Swift API.

RAC與Rx之間的關係?

未完待續

ReactiveCocoa was originally inspired, and therefore heavily influenced, by Microsoft's Reactive Extensions (Rx) library.There are many ports of Rx, including RxSwift , but ReactiveCocoa is intentionally not a direct port.

Where RAC differs from Rx, it is usually to:

  • Create a simpler API

  • Address common sources of confusion

  • More closely match Cocoa conventions

The following are some of the concrete differences, along with their rationales.

相關文章
相關標籤/搜索