ReactiveCocoa(RAC)

什么是ReactiveCocoa

ReactiveCocoa(其簡稱為RAC)是由Github開源的一個應用于iOS和OS X開發的新框架。RAC具有函數式編程和響應式編程的特性。它主要吸取了.Net的Reactive Extensions的設計和實現。

ReactiveCocoa試圖解決什么問題

經過一段時間的研究,我認為ReactiveCocoa試圖解決以下3個問題:

傳統iOS開發過程中,狀態以及狀態之間依賴過多的問題

傳統MVC架構的問題:Controller比較復雜,可測試性差

提供統一的消息傳遞機制

傳統iOS開發過程中,狀態以及狀態之間依賴過多的問題

我們在開發iOS應用時,一個界面元素的狀態很可能受多個其它界面元素或后臺狀態的影響。

例如,在用戶帳戶的登錄界面,通常會有2個輸入框(分別輸入帳號和密碼)和一個登錄按鈕。如果我們要加入一個限制條件:當用戶輸入完帳號和密碼,并且登錄的網絡請求還未發出時,確定按鈕才可以點擊。通常情況下,我們需要監聽這兩個輸入框的狀態變化以及登錄的網絡請求狀態,然后修改另一個控件的enabled狀態。

傳統的寫法如下(該示例代碼修改自ReactiveCocoa官網) :

12345678910111213141516171819202122232425262728293031

staticvoid*ObservationContext=&ObservationContext;-(void)viewDidLoad{[superviewDidLoad];[LoginManager.sharedManageraddObserver:selfforKeyPath:@"loggingIn"options:NSKeyValueObservingOptionInitialcontext:&ObservationContext];[self.usernameTextFieldaddTarget:selfaction:@selector(updateLogInButton)forControlEvents:UIControlEventEditingChanged];[self.passwordTextFieldaddTarget:selfaction:@selector(updateLogInButton)forControlEvents:UIControlEventEditingChanged];}-(void)updateLogInButton{BOOLtextFieldsNonEmpty=self.usernameTextField.text.length>0&&self.passwordTextField.text.length>0;BOOLreadyToLogIn=!LoginManager.sharedManager.isLoggingIn&&!self.loggedIn;self.logInButton.enabled=textFieldsNonEmpty&&readyToLogIn;}-(void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionary*)changecontext:(void*)context{if(context==ObservationContext){[selfupdateLogInButton];}else{[superobserveValueForKeyPath:keyPathofObject:objectchange:changecontext:context];}}

RAC通過引入信號(Signal)的概念,來代替傳統iOS開發中對于控件狀態變化檢查的代理(delegate)模式或target-action模式。因為RAC的信號是可以組合(combine)的,所以可以輕松地構造出另一個新的信號出來,然后將按鈕的enabled狀態與新的信號綁定。如下所示:

123456789

RAC(self.logInButton,enabled)=[RACSignalcombineLatest:@[self.usernameTextField.rac_textSignal,self.passwordTextField.rac_textSignal,RACObserve(LoginManager.sharedManager,loggingIn),RACObserve(self,loggedIn)]reduce:^(NSString*username,NSString*password,NSNumber*loggingIn,NSNumber*loggedIn){return@(username.length>0&&password.length>0&&!loggingIn.boolValue&&!loggedIn.boolValue);}];

可以看到,在引入RAC之后,以前散落在action-target或KVO的回調函數中的判斷邏輯被統一到了一起,從而使得登錄按鈕的enabled狀態被更加清晰地表達了出來。

除了組合(combine)之外,RAC的信號還支持鏈式(chaining)和過濾(filter),以方便將信號進行進一步處理。

試圖解決MVC框架的問題

對于傳統的Model-View-Controller的框架,Controller很容易變得比較龐大和復雜。由于Controller承擔了Model和View之間的橋梁作用,所以Controller常常與對應的View和Model的耦合度非常高,這同時也造成對其做單元測試非常不容易,對iOS工程的單元測試大多都只在一些工具類或與界面無關的邏輯類中進行。

RAC的信號機制很容易將某一個Model變量的變化與界面關聯,所以非常容易應用Model-View-ViewModel框架。通過引入ViewModel層,然后用RAC將ViewModel與View關聯,View層的變化可以直接響應ViewModel層的變化,這使得Controller變得更加簡單,由于View不再與Model綁定,也增加了View的可重用性。

因為引入了ViewModel層,所以單元測試可以在ViewModel層進行,iOS工程的可測試性也大大增強了。InfoQ也曾撰文介紹過MVVM:《MVVM啟示錄》

統一消息傳遞機制

iOS開發中有著各種消息傳遞機制,包括KVO、Notification、delegation、block以及target-action方式。各種消息傳遞機制使得開發者在做具體選擇時感到困惑,例如在objc.io上就有專門撰文破船的翻譯),介紹各種消息傳遞機制之間的差異性。

RAC將傳統的UI控件事件進行了封裝,使得以上各種消息傳遞機制都可以用RAC來完成。示例代碼如下:

123456789101112131415161718192021222324

// KVO[RACObserve(self,username)subscribeNext:^(idx){NSLog(@"成員變量 username 被修改成了:%@",x);}];// target-actionself.button.rac_command=[[RACCommandalloc]initWithSignalBlock:^RACSignal*(idinput){NSLog(@"按鈕被點擊");return[RACSignalempty];}];// Notification[[[NSNotificationCenterdefaultCenter]rac_addObserverForName:UIKeyboardDidChangeFrameNotificationobject:nil]subscribeNext:^(idx){NSLog(@"鍵盤Frame改變");}];// Delegate[[selfrac_signalForSelector:@selector(viewWillAppear:)]subscribeNext:^(idx){debugLog(@"viewWillAppear方法被調用 %@",x);}];

RAC的RACSignal類也提供了createSignal方法來讓用戶創建自定義的信號,如下代碼創建了一個下載指定網站內容的信號。

12345678910111213141516171819

-(RACSignal*)urlResults{return[RACSignalcreateSignal:^RACDisposable*(idsubscriber){NSError*error;NSString*result=[NSStringstringWithContentsOfURL:[NSURLURLWithString:@"http://www.devtang.com"]encoding:NSUTF8StringEncodingerror:&error];NSLog(@"download");if(!result){[subscribersendError:error];}else{[subscribersendNext:result];[subscribersendCompleted];}return[RACDisposabledisposableWithBlock:^{NSLog(@"clean up");}];}];}

如何使用ReactiveCocoa

ReactiveCocoa可以在iOS和OS X的應用開發中使用,對于iOS開發者,可以將RAC源碼下載編譯后,使用編譯好的libReactiveCocoa-iOS.a文件。

開發者也可以用CocoaPods來設置目標工程對ReactiveCocoa的依賴,只需要編輯Podfile文件,增加如下內容即可:

1

pod'ReactiveCocoa'

ReactiveCocoa的特點

RAC在應用中大量使用了block,由于Objective-C語言的內存管理是基于引用計數的,為了避免循環引用問題,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)來避免強引用。另外,在使用時應該注意block的嵌套層數,不恰當的濫用多層嵌套block可能給程序的可維護性帶來災難。

RAC的編程方式和傳統的MVC方式差異巨大,所以需要較長的學習時間。并且,業界內對于RAC并沒有廣泛應用,這造成可供參考的項目和教程比較欠缺。 另外,RAC項目本身也還在快速演進當中,1.x版本和2.x版本API改動了許多,3.0版本也正在快速開發中,對它的使用也需要考慮后期的升級維護問題。

作為一個iOS開發領域的新開源框架,ReactiveCocoa帶來了函數式編程和響應式編程的思想,值得大家關注并且學習。

一些學習資源

博客&教程

http://spin.atomicobject.com/2014/02/03/objective-c-delegate-pattern/

http://blog.bignerdranch.com/4549-data-driven-ios-development-reactivecocoa/

http://en.wikipedia.org/wiki/Functional_reactive_programming

http://www.teehanlax.com/blog/reactivecocoa/

http://www.teehanlax.com/blog/getting-started-with-reactivecocoa/

http://nshipster.com/reactivecocoa/

http://cocoasamurai.blogspot.com/2013/03/basic-mvvm-with-reactivecocoa.html

http://iiiyu.com/2013/09/11/learning-ios-notes-twenty-eight/

https://speakerdeck.com/andrewsardone/reactivecocoa-at-mobidevday-2013

http://msdn.microsoft.com/en-us/library/hh848246.aspx

http://www.itiger.me/?p=38

http://blog.leezhong.com/ios/2013/12/27/reactivecocoa-2.html

https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/FrameworkOverview.md

http://www.haskell.org/haskellwiki/Functional_Reactive_Programming

http://blog.zhaojie.me/2009/09/functional-reactive-programming-for-csharp.html

代碼

https://github.com/Machx/MVVM-IOS-Example

https://github.com/ReactiveCocoa/RACiOSDemo

書籍

https://leanpub.com/iosfrp

視頻

http://vimeo.com/65637501

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容