成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

譯文
移動開發(fā)
在這篇文章中,我要比較GitHub上提供的兩個最流行的函數響應式編程庫——RxSwift與ReactiveCocoa。

一、簡介

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

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

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

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

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

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

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

函數式編程(Functional Programming):強調通過數學語言風格的函數、不變性和表現力來實現計算,并最小化變量和狀態(tài)的使用。請參閱百度百科(http://baike.baidu.com/link?url=oTiEJsaX5ibGvK3R-BK6J55dGOXf3-Zzn5e1uBpvWDx4AjCV8ykQtRWz3RmuUefjD6IzL_QZcyedkvMB8sEyhK)進一步了解這種編程范式。

(一)一個簡單的例子

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

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

1.       創(chuàng)建一個能夠發(fā)出你能夠進行響應的位置事件的信息流。

2.       然后,你要對位置事件進行過濾,以便確定哪些位置事件對應于靠近咖啡館這種信息,然后發(fā)送相應的警告。

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

  1. locationProducer // 1 
  2.  
  3.   .filter(ifLocationNearCoffeeShops) // 2 
  4.  
  5.   .startWithNext {[weak self] location in // 3 
  6.  
  7.     self?.alertUser(location) 
  8.  

下面作簡要分析。

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

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

3. ***,startWithNext形成對過濾后信號的訂閱。于是每當事件到達,閉包中的表達式都被執(zhí)行。

上面的代碼看上去與轉換值數組的代碼極其相似。但是這里有一點特別“聰明”——這段代碼是異步執(zhí)行的;隨著位置事件的發(fā)生filter函數和閉包表達式被相應地調用。

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

(二)事件轉換

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

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

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

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

  1. locationProducer 
  2.  
  3.   .skipRepeats() // 1 
  4.  
  5.   .filter(ifLocationNearCoffeeShops) 
  6.  
  7.   .map(toHumanReadableLocation) // 2 
  8.  
  9.   .startWithNext {[weak self] readableLocation in 
  10.  
  11.     self?.alertUser(readableLocation) 
  12.  

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

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

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

至此,你應該了解了FRP編程的優(yōu)點:

簡單有力;

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

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

三、ReactiveCocoa與RxSwift框架簡介

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

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

(一)ReactiveCocoa框架

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

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

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

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

(二)RxSwift框架

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

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

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

四、ReactiveCocoa與RxSwift框架比較

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

(一)熱信號與冷信號

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

  1. let requestFlow = networkRequest.flatMap(parseResponse) 
  2.  
  3. requestFlow.startWithNext {[weak self] result in 
  4.  
  5.   self?.showResult(result) 
  6.  

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

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

讓我們回顧一下:

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

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

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

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

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

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

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

(二) 錯誤處理

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

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

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

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

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

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

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

  1. create { observer in 
  2.  
  3.   observer.onError(NSError.init(domain: "NetworkServer", code: 1, userInfo: nil)) 
  4.  

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

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

  1. create { observer in 
  2.  
  3.   observer.onError(MyDomainSpecificError.NetworkServer) 
  4.  

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

  1. enum MyDomanSpecificError: ErrorType { 
  2.  
  3.   case NetworkServer 
  4.  
  5.   case Parser 
  6.  
  7.   case Persistence 
  8.  
  9.  
  10.  
  11. func handleError(error: MyDomanSpecificError) { 
  12.  
  13.   // Show alert with the error 
  14.  
  15.  
  16. observable.subscribeError {[weak self] error in 
  17.  
  18.   self?.handleError(error) 
  19.  
  20.  } 

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

1.嘗試把error轉換成MyDomanSpecificError。

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

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

 

  1. enum MyDomanSpecificError: ErrorType { 
  2.  
  3.   case NetworkServer 
  4.  
  5.   case Parser 
  6.  
  7.   case Persistence 
  8.  
  9.   case Unknown 
  10.  
  11.  
  12. observable.subscribeError {[weak self] error in 
  13.  
  14.   self?.handleError(error as? MyDomanSpecificError ?? .Unknown) 
  15.  

 

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

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

(三) UI綁定

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

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

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

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

為了彌補這種情況,你可以自行查閱一部分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。有許多人可以繼續(xù)開展這項工作,而且有相當數量的在線教程。此外,StackOverflow網站也提供了專門針對它(https://stackoverflow.com/questions/tagged/reactive-cocoa)的子論壇。

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

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

(五)使用哪一個更好

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

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

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

建議選擇ReactiveCocoa框架:

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

如果你想使用大規(guī)模測試框架,為許多人使用,并應用于許多項目中。

建議選擇RxSwift框架:

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

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

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

五、小結

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

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

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

Conal Elliott的博客(http://conal.net/blog/);

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

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

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

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

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

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

RxSwift探討資源(http://rx-marin.com/)。

原文標題:ReactiveCocoa vs RxSwift

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

責任編輯:李英杰 來源: 51CTO
相關推薦

2015-05-07 10:10:29

GitHub編程語言

2015-05-04 10:05:11

編程語言GitHub流行語言

2014-04-28 10:51:24

GitHubJava庫

2016-09-07 14:29:13

GitHub安全SQL

2022-07-20 10:01:23

MonorepoReact

2014-02-04 19:44:23

編程語言開發(fā)

2025-03-13 00:35:00

2011-03-21 13:01:10

2016-08-22 08:36:14

ReactiveCoc內存泄漏GitHub

2021-07-14 13:12:51

2017-06-27 14:02:09

前端框架Bootstrap

2018-03-13 09:34:30

人工智能編程語言Python

2017-07-14 14:50:00

架構框架前端

2009-11-06 10:48:14

函數式編程Scala

2021-03-02 09:00:00

開源框架技術

2019-01-30 12:38:41

JavaScript前端編程語言

2011-06-16 08:22:04

JavaScriptjQuery

2023-11-20 10:49:51

2013-06-27 09:31:37

聲明式編程命令式編程編程

2017-06-08 14:25:46

Kotlin函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩成人在线一区 | 四虎在线播放 | 毛片免费观看 | 亚洲一一在线 | .国产精品成人自产拍在线观看6 | 久久精品免费一区二区 | h视频在线看 | 日本中出视频 | 成人午夜在线观看 | а√中文在线8 | 干干天天 | 亚洲综合国产 | 天天躁日日躁xxxxaaaa | 国产日韩一区二区 | 欧美亚洲一区二区三区 | 久久国产精彩视频 | 亚洲精品一区二区在线观看 | 亚洲精品久久久久久一区二区 | www.9191 | 国产视频亚洲视频 | 美日韩精品| jizz在线免费观看 | 国产高清一区二区 | 日韩欧美手机在线 | 成人精品啪啪欧美成 | 色网站在线免费观看 | 欧洲毛片 | 一区二区三区免费 | 亚洲综合在线一区 | 久久综合影院 | 久久精彩 | 精品欧美一区二区三区久久久小说 | 成人av一区 | 日韩高清电影 | 日本不卡免费新一二三区 | 婷婷久久一区 | 国产精品久久欧美久久一区 | 黄色毛片在线观看 | 精品一二 | 成人亚洲| 精品99在线|