SEO優化 GitHub上最流行的函數響應式編程庫:ReactiveCocoa與RxSwift框架大比較

一、簡介

如今,函數響應式編程成為越來越受Swift開發商歡迎的編程方法。原因很簡單,它能使復雜的異步代碼容易地編寫和理解。

在這篇文章中,我要比較GitHub上提供的兩個最流行的函數響應式編程庫——RxSwift與ReactiveCocoa。

首先,我們將簡要回顧什麼是函數響應式編程,然後詳細比較這兩個框架。本文結束時,你會決定哪一個框架更適合你!

二、什麼是函數響應式編程(FRP)

甚至在蘋果公司宣佈Swift語言之前,函數響應式編程在近幾年已人氣劇增,從而與面向對象編程形成鮮明對比。從Haskell到Javascript,你都能夠發現其中包含著受函數響應式編程啟發而存在的支持。這是為什麼?函數響應式編程提供了什麼特別的支持?也許最重要的是,你該怎樣在Swift編程中使用這一技術?

FRP是一種由Conal Elliott創建的編程範式。他定義了有關FRP的非常具體的語義(請參考https://stackoverflow.com/questions/1028250/what-is-functional-reactive-programming)。為了實現更簡潔的定義,FRP組合了另外兩個功能概唸:

l  響應式編程(Reactive Programming):側重於異步數據流,你可以監聽這種數據流並迅速做出相應的反應。要了解與之相關的更多信息,請查閱https://gist.github.com/staltz/868e7e9bc2a7b8c1f754。

l  函數式編程(Functional Programming):強調通過數學語言風格的函數、不變性和表現力來實現計算,並最小化變量和狀態的使用。請參閱百度百科(

(一)一個簡單的例子

當然,理解上述概唸的最容易的方式是通過一個簡單的實例加以說明。現在,我們來搆建一個小程序,它將實現用戶位置的定位功能,並當該用戶靠近一家咖啡館時及時地通知他。

如果你想使用函數響應式編程來開發上述程序,你需要:

1.       創建一個能夠發出你能夠進行響應的位置事件的信息流。

2.       然後,你要對位置事件進行過濾,以便確定哪些位置事件對應於靠近咖啡館這種信息,然後發送相應的警告,台南網頁設計

使用ReactiveCocoa編程實現上述功能的代碼大緻如下所示:

下面作簡要分析。

1. locationProducer負責每當位置改變時發出一個事件。注意:這在ReactiveCocoa編程中稱作“信號”(signal),而在RxSwift中稱作“順序”(sequence)。

2. 然後,使用函數編程技術來響應位置更新。filter方法執行與數組上過濾操作完全相同的功能,負責把每個值傳遞給函數ifLocationNearCoffeeShops。如果該函數返回true,台中網頁設計,則該事件被允許進行下一步處理。

3. 最後,startWithNext形成對過濾後信號的訂閱。於是每當事件到達,閉包中的表達式都被執行。

上面的代碼看上去與轉換值數組的代碼極其相似。但是這裏有一點特別“聰明”——這段代碼是異步執行的;隨著位置事件的發生filter函數和閉包表達式被相應地調用,台中網頁設計

當然,你可能會對其所用語法感到有點奇怪,但希望這段代碼的基本意圖你應該清楚。這就是函數式編程的美麗所在:它是聲明性語言。它向你展示發生了什麼,而不是如何能做的細節實現。

(二)事件轉換

在上面的定位示例中,你才剛剛學會如何觀察(observe)流,除了過濾出咖啡館附近位置信息外,你其實並沒有對這些事件做更多的事情。

FRP的另一個基本點是把這些事件組合一起並把它們轉換為有意義的內容。為此,你要使用(但不限於)高階函數。

不出所料,你會在Swift函數式編程中經常遇到如下內容:map、filter、reduce、combine和zip。

讓我們修改一下上面的定位示例,台中網頁設計,以便跳過重復的位置信息而把傳入的位置信息(對應於CLLocation結搆)轉換成更富人性化的消息。

下面讓我們來分析一下上面新添加的兩行代碼:

1.       首先對通過locationProducer發出的信號應用skipRepeats操作。注意,這種操作並沒有模儗數組的意思,而是ReactiveCocoa特有的。其執行的函數功能是很容易理解的:過濾掉重復的事件。

2.       在執行過濾函數後,調用map來把事件數據從一種類型轉換成另一種類型,有可能從CLLocation轉換成String。

至此,你應該了解了FRP編程的優點:

l  簡單有力;

l  基於聲明式表達方式便代碼更易於理解;

l  復雜的流程變得更易於管理和描述。

三、ReactiveCocoa與RxSwift框架簡介

現在,你已經更好地了解了FRP是什麼以及它如何可以幫助你使復雜的異步流更容易管理。接下來,讓我們考察兩個當前最受歡迎的FRP框架——ReactiveCocoa和RxSwift,seo,並進一步了解為什麼你可能選擇其中之一。

在正式討論有關細節之前,讓我們簡要介紹一下每個框架的歷史。

(一)ReactiveCocoa框架

ReactiveCocoa框架(https://github.com/ReactiveCocoa/ReactiveCocoa)發佈在GitHub網站上。在GitHub Mac客戶端上工作時,SEO優化,開發人員發現自己疲於應對其應用程序的數據流。他們從微軟的ReactiveExtensions(一個針對C#的FRP框架)框架中找到靈感,然後開發出他們自己的Objective-C實現版本。

當開發團隊正在他們Objective-C3.0版本上進行研發時Swift正式宣佈發行。他們意識到,Swift的函數天性正好彌補了ReactiveCocoa,於是他們馬上著手實現Swift上的3.0版本。該3.0版本充分地利用了柯裏化(curring)和pipe-forward運算符技術。

Swift 2.0引入了面向協議編程思想,從而導緻ReactiveCocoa API發展歷程中的另一個重大變化,隨著版本4.0發佈的臨近,pipe-forward運算符支持協議擴展。

在本文寫作之時,ReactiveCocoa已經成為一個GitHub網站上點讚超過13,000星的大熱庫。

(二)RxSwift框架

微軟的ReactiveExtensions啟發了大量的框架把FRP概唸加入到JavaScript、Java、Scala和其他眾多語言中。這最終導緻ReactiveX的形成。ReactiveX其實是一個開發小組,它能夠創建一批針對FRP實現的通用API;這將允許不同的框架開發人員協同工作。其結局是,熟悉Scala的RxScala開發人員能夠相對容易過渡到Java的等效實現——RxJava。

RxSwift是最近才加入到ReactiveX中的,因此目前還沒有像ReactiveCocoa(在本文寫作之時,在GitHub已經獲得大約4,000個星的點讚)那樣普及。然而,RxSwift是ReactiveX的一部分的事實無疑將有助於它的流行和長久化。

有趣的是,RxSwift和ReactiveCocoa分享著一個共同的祖代實現——ReactiveExtensions!

四、ReactiveCocoa與RxSwift框架比較

承接前面所提到的,現在我們來關注細節內容。ReactiveCocoa與RxSwift框架在FRP支持方面擁有許多的不同之處。在此僅討論幾個關鍵部分。

(一)熱信號與冷信號

想象一下,你需要發出網絡請求、解析響應並向用戶顯示有關信息,例如類似於下面的代碼:

當訂閱信號(使用startWithNext)時,將啟動網絡請求。這些信號被稱為“冷”信號,因為它們處於“凍結”狀態——直到你實際上訂閱這些信號。

另一方面是“熱”信號。當訂閱其中之一時,它可能已經啟動;因此,你正在觀察的可能是第三或第四個相應的事件。一種典型的例子是敲打鍵盤。所謂“開始”敲打其實並無多大意義,對於服務器請求也是如此。

讓我們回顧一下:

l  冷信號是:當你訂閱它時你才啟動。每個新的訂閱服務器啟動這項工作。訂閱requestFlow三次意味著發出三次網絡請求。

l  熱信號是:已經可以發送事件。新的訂閱服務器不去啟動它。通常,UI交互就是熱信號。

ReactiveCocoa針對熱信號和冷信號提供了對應的類型支持:Signal<T, E>和SignalProducer<T, E>。然而,RxSwift使用了一種適用於上述兩種類型的結搆Observable<T>。

提供不同的類型來表示熱和冷信號有必要嗎?

就個人而言,我發現了解信號的語義是很重要的,因為它更好地描述了如何在特定的語境中使用它。當處理復雜的係統時,這可能有很大的區別。

且不說是否提供不同類型,僅了解熱和冷信號而言就非常重要。

假設你正在處理一個熱信號,但經證明它原來是一個冷信號,針對每個新的訂閱服務器你將會以副作用方式啟動,這對你的應用程序可能產生巨大的影響。一個常見的例子就是,在你的應用程序中存在三個或四個地方想觀察網絡請求,桃園網頁設計,而針對每一個新的訂閱將開始一個不同的請求。

(二) 錯誤處理

讓我們談到錯誤處理之前,不妨扼要地重述一下在RxSwift和ReactiveCocoa中調度的事件性質。在這兩個框架中,都提供了三個主要事件:

1.         Next<T>:每當有新值(類型T)推入到事件流時,將發送此事件。在上面的定位器示例中,T是CLLocation。

2.         Completed:指示事件流已經結束。此事件發生後,不再發送Next <T>或Error <E>。

3.         Error:指示一個錯誤。在上面的服務器請求示例中,如果你有一個服務器錯誤,會發送此事件。E描述了符合ErrorType協議的數據類型。此事件發生後,不會再發送Next或者Completed。

你可能已經注意到在前面討論熱和冷信號內容時ReactiveCocoa中的Signal<T,E>和SignalProducer<T,E>都使用了兩個參數化的類型,而RxSwift的Observable <T>僅提供了一個。其中,第二種類型(E)是指符合ErrorType協議的類型。在RxSwift中,該類型被忽略,而在內部被視為一種符合ErrorType協議的類型。

那麼,這一切意味著什麼呢?

用通俗易懂的話說,它意味著在RxSwift 中可以通過多種不同的方式發出錯誤信息:

上述代碼創建了一個信號(或使用RxSwift術語來說,是一個可觀察的序列)並立即發出一個錯誤。

下面給出一種可替代的表達方式:

因為一個Observable只強制要求錯誤必須是符合ErrorType協議的類型,所以,你差不多可以發送任何你想要的。但也有一點尷尬的問題,請參考如下代碼:

上述代碼是不會工作的,因為函數handleError期待是MyDomainSpecificError類型而不是ErrorType。為此,你被迫要做兩件事:

1.嘗試把error轉換成MyDomanSpecificError。

2.當不能把error轉換成MyDomanSpecificError時,自己來處理這種情況。

第一點可以輕易通過as?語法技術加以修復,但第二種情況較難處理一些。一種潛在的解決方案是引入一種Unknown類型:

在ReactiveCocoa中,當創建一個Signal<T,E>或SignalProducer<T,E>時因為你作了類型“修復”,如果你嘗試發送別的東西時編譯器會發出抱怨。因此,底線是:在ReactiveCocoa中,編譯器僅允許發送與你期望相同的錯誤。

這是ReactiveCocoa值得點讚的又一個方面!

(三) UI綁定

標準iOSAPI,如UIKit,並不使用FRP。為了使用RxSwift或ReactiveCocoa,你必須彌合這些Api,例如把設備的點按操作轉換成信號或可觀測對象。

正如你所想象的,這其中蘊藏著“巨大能量”;為此,ReactiveCocoa和RxSwift都各自提供大量的橋接函數及開箱即用的綁定支持。

ReactiveCocoa從其早期的Objective C時代帶來了很多好東西。你會發現已經做了大量的工作,這已經彌合了與Swift共同使用的問題。這其中包括UI綁定,以及其他目前尚未繙譯為Swift的運算符。當然,這稍微有點奇怪,你正在使用不屬於SwiftAPI部分(如RACSignal)的一些數據類型,這將迫使用戶把Objective C類型轉換為Swift類型。

不只如此,我覺得我們花費了更多時間來討論源碼而不是文檔,這已經慢慢地落後於時代了。不過,要注意的是,文檔從理論角度看的確是優秀的,只是沒有更多地關注實用方面。

為了彌補這種情況,網頁設計,你可以自行查閱一部分ReactiveCocoa教程。

另一方面,台中網頁設計,RxSwift綁定易於使用!不只是提供了一個龐大的分類目錄(https://github.com/ReactiveX/RxSwift/blob/master/Documentation/API.md),也提供了大量的範例(https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Examples.md),以及更完整的文檔(https://github.com/ReactiveX/RxSwift/tree/master/Documentation)。對於一些人來說,這已經是選擇RxSwift而勝過選擇ReactiveCocoa的足夠理由。

這是RxSwift值得點讚的又一個方面!

(四)社團支持

ReactiveCocoa出現的歷史已經遠遠超過RxSwift。有許多人可以繼續開展這項工作,而且有相當數量的在線教程。此外,StackOverflow網站也提供了專門針對它(https://stackoverflow.com/questions/tagged/reactive-cocoa)的子論壇。

ReactiveCocoa有一個專門的Slack群,但很小,只有209人,所以經常有很多問題未得到及時解答。在緊急關頭,我有時不得不聯係ReactiveCocoa核心成員請教,當然假設別人也有類似的需求,台北網頁製作公司。儘管如此,你最有可能找到一些在線教程來解釋你的問題。

相對於ReactiveCocoa,RxSwift自然更新一些,目前基本呈現出“很多人看一個人表演”的狀態。它也有一個專門的Slack群,有961名成員,而且面臨著比這個數目大得多的討論量。如果有相關問題,你總能在此群中找到人來幫助你。

(五)使用哪一個更好

讀者Ash Furrow的建議是:如果你是一位新手,那麼選擇從哪一個框架開始都無所謂。不錯,的確存在許多技術方面的不同,但是對於新手來說這些內容都是很有意思的。你可以嘗試使用一個框架,再試試另一個框架。由你自己確定到底哪一個更符合你自己,然後你就能夠理解你為什麼選擇這個框架了。

如果你是一位新手,我也建議你這樣做。其實,只有你積累了足夠豐富的經驗時你才會欣賞到二者之間的奧妙區別。

但是,如果你擔任著一種特殊職務,你需要選擇其一,並且沒有時間來隨意體驗,那麼我的建議如下:

建議選擇ReactiveCocoa框架:

l  如果你想更好地描述你的係統。並且,想使用不同的類型來區別熱信號和冷信號,並且在錯誤處理方面使用類型化參數,這些會為你的係統開發帶來驚喜。

l  如果你想使用大規模測試框架,為許多人使用,並應用於許多項目中。

建議選擇RxSwift框架:

l  如果UI綁定對你的工程很重要。

l  如果你是一位FRP新手,並需要及時的幫助信息。

l  如果你已經了解了RxJS或者RxJava。那麼,既然這兩個框架和RxSwift框架都隸於Reactivex組織,一旦你熟悉了其中之一,剩下的也就是語法問題了。

五、小結

無論選擇RxSwift還是ReactiveCocoa框架,你都不會後悔的。這兩個都是功能極其強大的框架,都會幫助你更好地描述你的係統。

值得注意的是,一旦你選擇了RxSwift還是ReactiveCocoa框架,在兩者之間來回切換只是幾個小時的問題。就我的體驗來說,從ReactiveCocoa轉到RxSwift最關鍵的是熟悉其錯誤處理技術。總之,最關鍵的問題在於克服FRP編程技術,而不是具體的實現方面。

最後,提供幾個鏈接供你在學習上述兩個框架道路上作為參考:

l  Conal Elliott的博客(

l  Conal Elliott在Stackoverflow網站上的重要問答(https://stackoverflow.com/questions/1028250/what-is-functional-reactive-programming);

l  André Staltz的重要文章“Why I cannot say FRP but I just did”(https://medium.com/@andrestaltz/why-i-cannot-say-frp-but-i-just-did-d5ffaa23973b#.62dnhk32p);

l  RxSwift代碼倉庫(https://github.com/ReactiveX/RxSwift);

l  ReactiveCocoa代碼倉庫(https://github.com/ReactiveCocoa/ReactiveCocoa);

l  Rex代碼倉庫(https://github.com/neilpa/Rex);

l  針對iOS開發者的FRP寶庫(https://gist.github.com/JaviLorbada/4a7bd6129275ebefd5a6)。

l  RxSwift探討資源(

原文標題:ReactiveCocoa vs RxSwift

【51CTO.com獨家譯文,合作站點轉載請注明來源】

【編輯推薦】

【責任編輯:李英傑 TEL:(010)68476606】

點讚 0