ReactiveCocoa(RAC)

什么是ReactiveCocoa

ReactiveCocoa(其簡稱為RAC)是由Github開源的一個(gè)應(yīng)用于iOS和OS X開發(fā)的新框架忍抽。RAC具有函數(shù)式編程和響應(yīng)式編程的特性雅倒。它主要吸取了.Net的Reactive Extensions的設(shè)計(jì)和實(shí)現(xiàn)。

ReactiveCocoa試圖解決什么問題

經(jīng)過一段時(shí)間的研究仑乌,我認(rèn)為ReactiveCocoa試圖解決以下3個(gè)問題:

傳統(tǒng)iOS開發(fā)過程中,狀態(tài)以及狀態(tài)之間依賴過多的問題

傳統(tǒng)MVC架構(gòu)的問題:Controller比較復(fù)雜,可測(cè)試性差

提供統(tǒng)一的消息傳遞機(jī)制

傳統(tǒng)iOS開發(fā)過程中,狀態(tài)以及狀態(tài)之間依賴過多的問題

我們?cè)陂_發(fā)iOS應(yīng)用時(shí)禁荒,一個(gè)界面元素的狀態(tài)很可能受多個(gè)其它界面元素或后臺(tái)狀態(tài)的影響。

例如角撞,在用戶帳戶的登錄界面呛伴,通常會(huì)有2個(gè)輸入框(分別輸入帳號(hào)和密碼)和一個(gè)登錄按鈕。如果我們要加入一個(gè)限制條件:當(dāng)用戶輸入完帳號(hào)和密碼谒所,并且登錄的網(wǎng)絡(luò)請(qǐng)求還未發(fā)出時(shí)热康,確定按鈕才可以點(diǎn)擊。通常情況下劣领,我們需要監(jiān)聽這兩個(gè)輸入框的狀態(tài)變化以及登錄的網(wǎng)絡(luò)請(qǐng)求狀態(tài)姐军,然后修改另一個(gè)控件的enabled狀態(tài)。

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

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通過引入信號(hào)(Signal)的概念尖淘,來代替?zhèn)鹘y(tǒng)iOS開發(fā)中對(duì)于控件狀態(tài)變化檢查的代理(delegate)模式或target-action模式奕锌。因?yàn)镽AC的信號(hào)是可以組合(combine)的,所以可以輕松地構(gòu)造出另一個(gè)新的信號(hào)出來村生,然后將按鈕的enabled狀態(tài)與新的信號(hào)綁定惊暴。如下所示:

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的回調(diào)函數(shù)中的判斷邏輯被統(tǒng)一到了一起辽话,從而使得登錄按鈕的enabled狀態(tài)被更加清晰地表達(dá)了出來。

除了組合(combine)之外卫病,RAC的信號(hào)還支持鏈?zhǔn)剑╟haining)和過濾(filter)油啤,以方便將信號(hào)進(jìn)行進(jìn)一步處理。

試圖解決MVC框架的問題

對(duì)于傳統(tǒng)的Model-View-Controller的框架蟀苛,Controller很容易變得比較龐大和復(fù)雜益咬。由于Controller承擔(dān)了Model和View之間的橋梁作用,所以Controller常常與對(duì)應(yīng)的View和Model的耦合度非常高帜平,這同時(shí)也造成對(duì)其做單元測(cè)試非常不容易幽告,對(duì)iOS工程的單元測(cè)試大多都只在一些工具類或與界面無關(guān)的邏輯類中進(jìn)行。

RAC的信號(hào)機(jī)制很容易將某一個(gè)Model變量的變化與界面關(guān)聯(lián)罕模,所以非常容易應(yīng)用Model-View-ViewModel框架评腺。通過引入ViewModel層,然后用RAC將ViewModel與View關(guān)聯(lián)淑掌,View層的變化可以直接響應(yīng)ViewModel層的變化蒿讥,這使得Controller變得更加簡單,由于View不再與Model綁定抛腕,也增加了View的可重用性芋绸。

因?yàn)橐肓薞iewModel層,所以單元測(cè)試可以在ViewModel層進(jìn)行担敌,iOS工程的可測(cè)試性也大大增強(qiáng)了摔敛。InfoQ也曾撰文介紹過MVVM:《MVVM啟示錄》

統(tǒng)一消息傳遞機(jī)制

iOS開發(fā)中有著各種消息傳遞機(jī)制全封,包括KVO马昙、Notification桃犬、delegation、block以及target-action方式行楞。各種消息傳遞機(jī)制使得開發(fā)者在做具體選擇時(shí)感到困惑攒暇,例如在objc.io上就有專門撰文破船的翻譯),介紹各種消息傳遞機(jī)制之間的差異性子房。

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

123456789101112131415161718192021222324

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

RAC的RACSignal類也提供了createSignal方法來讓用戶創(chuàng)建自定義的信號(hào)证杭,如下代碼創(chuàng)建了一個(gè)下載指定網(wǎng)站內(nèi)容的信號(hào)田度。

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的應(yīng)用開發(fā)中使用,對(duì)于iOS開發(fā)者解愤,可以將RAC源碼下載編譯后镇饺,使用編譯好的libReactiveCocoa-iOS.a文件。

開發(fā)者也可以用CocoaPods來設(shè)置目標(biāo)工程對(duì)ReactiveCocoa的依賴琢歇,只需要編輯Podfile文件兰怠,增加如下內(nèi)容即可:

1

pod'ReactiveCocoa'

ReactiveCocoa的特點(diǎn)

RAC在應(yīng)用中大量使用了block,由于Objective-C語言的內(nèi)存管理是基于引用計(jì)數(shù)的李茫,為了避免循環(huán)引用問題揭保,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)來避免強(qiáng)引用魄宏。另外秸侣,在使用時(shí)應(yīng)該注意block的嵌套層數(shù),不恰當(dāng)?shù)臑E用多層嵌套block可能給程序的可維護(hù)性帶來災(zāi)難宠互。

RAC的編程方式和傳統(tǒng)的MVC方式差異巨大味榛,所以需要較長的學(xué)習(xí)時(shí)間。并且予跌,業(yè)界內(nèi)對(duì)于RAC并沒有廣泛應(yīng)用搏色,這造成可供參考的項(xiàng)目和教程比較欠缺。 另外券册,RAC項(xiàng)目本身也還在快速演進(jìn)當(dāng)中频轿,1.x版本和2.x版本API改動(dòng)了許多,3.0版本也正在快速開發(fā)中烁焙,對(duì)它的使用也需要考慮后期的升級(jí)維護(hù)問題航邢。

作為一個(gè)iOS開發(fā)領(lǐng)域的新開源框架,ReactiveCocoa帶來了函數(shù)式編程和響應(yīng)式編程的思想骄蝇,值得大家關(guān)注并且學(xué)習(xí)膳殷。

一些學(xué)習(xí)資源

博客&教程

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市九火,隨后出現(xiàn)的幾起案子赚窃,更是在濱河造成了極大的恐慌册招,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件考榨,死亡現(xiàn)場離奇詭異跨细,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)河质,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來震叙,“玉大人掀鹅,你說我怎么就攤上這事∶铰ィ” “怎么了乐尊?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長划址。 經(jīng)常有香客問我扔嵌,道長,這世上最難降的妖魔是什么夺颤? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任痢缎,我火速辦了婚禮,結(jié)果婚禮上世澜,老公的妹妹穿的比我還像新娘独旷。我一直安慰自己,他們只是感情好寥裂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布嵌洼。 她就那樣靜靜地躺著,像睡著了一般封恰。 火紅的嫁衣襯著肌膚如雪麻养。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天诺舔,我揣著相機(jī)與錄音鳖昌,去河邊找鬼。 笑死混萝,一個(gè)胖子當(dāng)著我的面吹牛遗遵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逸嘀,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼车要,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了崭倘?” 一聲冷哼從身側(cè)響起翼岁,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤类垫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后琅坡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悉患,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年榆俺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了售躁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茴晋,死狀恐怖陪捷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诺擅,我是刑警寧澤市袖,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站烁涌,受9級(jí)特大地震影響苍碟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撮执,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一微峰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧二打,春花似錦县忌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瑞信,卻和暖如春厉颤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凡简。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工逼友, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秤涩。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓帜乞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親筐眷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子黎烈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容