? ? ? ? 身為RAC的小白表谊,希望可以和大家討論一下關(guān)于ReactiveCocoa,這個(gè)采用函數(shù)響應(yīng)式編程(FRP)的框架,以下會(huì)對(duì)ReactiveCocoa簡(jiǎn)稱為RAC。
? ? ? ? 之前看過一遍文章,說的是作為一個(gè)iOS開發(fā)者昂验,寫的每一行代碼幾乎都是在相應(yīng)某個(gè)事件缘滥,例如按鈕的點(diǎn)擊,收到網(wǎng)絡(luò)消息惩坑,屬性的變化(通過KVO)或者用戶位置的變化(通過CoreLocation)掉盅。但是這些事件都用不同的方式來處理,比如action以舒、delegate趾痘、KVO、callback等蔓钟。我很贊同這種說法永票,于是,即然這樣的話,那我們?yōu)槭裁床话堰@些需要響應(yīng)的事件流統(tǒng)一放在一起呢瓦侮。很幸運(yùn)的是艰赞,Github有一個(gè)開源項(xiàng)目,即ReactiveCocoa簡(jiǎn)稱RAC肚吏,就是基于響應(yīng)式編程思想的Objective-C實(shí)踐方妖。
? ? ? ? ? 那么何為RAC呢?
? ? ? ? ?RAC是為應(yīng)用中發(fā)生的不同事件流提供了一個(gè)標(biāo)準(zhǔn)接口罚攀,我們可以使用一些基本工具來更容易的連接党觅、過濾和組合。
RAC結(jié)合了幾種編程風(fēng)格:
? ? ? ?函數(shù)式編程(Functional Programming):使用高階函數(shù)斋泄,例如函數(shù)用其他函數(shù)作為參數(shù)杯瞻。
? ? ? ?那么什么是函數(shù)式編程呢??
? ? ? ? 簡(jiǎn)單的一句話說炫掐,『盡量將操作都寫在一起魁莉,也就是寫成一個(gè)嵌套的函數(shù)』這就是函數(shù)式編程的核心思想,代表性項(xiàng)目 AFN
而它的本質(zhì)就是募胃,往方法里面?zhèn)魅隻lock , 方法里面在嵌套block.
? ? ? ? ? 響應(yīng)式編程(Reactive Programming):關(guān)注于數(shù)據(jù)流和變化傳播旗唁。
? ? ? ? ? 其實(shí)大家都接觸過響應(yīng)式編程,就是所謂的KVO痹束。
? ? ? ? ? KVO 大家肯定都接觸過吧检疫?一個(gè)屬性的改變立刻做出反應(yīng),我不管你的屬性有沒有值祷嘶,我不管你的屬性來了沒有屎媳,我就是監(jiān)聽,只要你一來我就做出響應(yīng)论巍,其實(shí)KVO的本質(zhì)就是烛谊,監(jiān)聽一個(gè)對(duì)象,他有沒有監(jiān)聽set方法嘉汰。然后將set方法重寫晒来。RAC 就是典型的響應(yīng)式編程,我信號(hào)發(fā)出去之后訂閱者就是負(fù)責(zé)監(jiān)聽郑现,不管你來不來,不管你有沒有荧降,反正我就是監(jiān)聽著接箫,只要你一來我就做出反應(yīng)。
? ? ? ? ?所以朵诫,你可能聽說過ReactiveCocoa被描述為函數(shù)響應(yīng)式編程(FRP)框架辛友。
? ? ? ? 有句比喻很好很形象的對(duì)RAC做了總結(jié):“可以把信號(hào)想象成水龍頭,只不過里面不是水,而是玻璃球(value)废累,直徑跟水管的內(nèi)徑一樣邓梅,這樣就能保證玻璃球是依次排列,不會(huì)出現(xiàn)并排的情況(數(shù)據(jù)都是線性處理的邑滨,不會(huì)出現(xiàn)并發(fā)情況)日缨。水龍頭的開關(guān)默認(rèn)是關(guān)的,除非有了接收方(subscriber)掖看,才會(huì)打開匣距。這樣只要有新的玻璃球進(jìn)來,就會(huì)自動(dòng)傳送給接收方哎壳∫愦可以在水龍頭上加一個(gè)過濾嘴(filter),不符合的不讓通過归榕,也可以加一個(gè)改動(dòng)裝置尸红,把球改變成符合自己的需求(map)。也可以把多個(gè)水龍頭合并成一個(gè)新的水龍頭(combineLatest:reduce:)刹泄,這樣只要其中的一個(gè)水龍頭有玻璃球出來外里,這個(gè)新合并的水龍頭就會(huì)得到這個(gè)球⊙”--? 來自博文http://blog.csdn.net/xdrt81y/article/details/30624469
首先導(dǎo)入RAC框架:
可以通過CocoaPods導(dǎo)入RAC框架:(注意RAC的版本)
導(dǎo)入? pod 'ReactiveCocoa', '~> 2.4.0' ?&& ?use_frameworks! #導(dǎo)入才不會(huì)報(bào)錯(cuò)?
或者? 導(dǎo)入pod 'ReactiveObjC', '~> 3.0.0'
? ? ? ? ReactiveCocoa 2.5以后引入Swift级乐,所以我們?cè)贠C開發(fā)中需要配入之前的版本,否則會(huì)錯(cuò)的一發(fā)不可收拾哦O亟场7缈啤!F虻贼穆!
? ? ? ? RAC為應(yīng)用中發(fā)生的不同事件流提供了一個(gè)標(biāo)準(zhǔn)接口。在ReactiveCocoa術(shù)語中這個(gè)叫做信號(hào)(signal)兰粉,由RACSignal類表示故痊。
? ? ? ? ReactiveCocoa signal(RACSignal)發(fā)送事件流給它的subscriber(訂閱者)。目前總共有三種類型的事件:next玖姑、error愕秫、completed。一個(gè)signal在因error終止或者完成前焰络,可以發(fā)送任意數(shù)量的next事件戴甩。RACSignal有很多方法可以來訂閱不同的事件類型。每個(gè)方法都需要至少一個(gè)block闪彼,當(dāng)事件發(fā)生時(shí)就會(huì)執(zhí)行block中的邏輯甜孤。
那么下面來一下實(shí)戰(zhàn)操作吧!!=纱ā\猿怼!
一把夸、創(chuàng)建信號(hào)
? ? ? ? 使用RACSignal的createSignal:方法來創(chuàng)建信號(hào)而线。方法的參數(shù)是一個(gè)block,這個(gè)block描述了這個(gè)信號(hào)扎即。當(dāng)這個(gè)信號(hào)有subscriber時(shí)吞获,block里的代碼就會(huì)執(zhí)行。
? ? ? ?block的參數(shù)是一個(gè)subscriber實(shí)例谚鄙,它遵循RACSubscriber協(xié)議各拷,協(xié)議里有一些方法來產(chǎn)生事件,你可以發(fā)送任意數(shù)量的next事件闷营,或者用error\complete事件來終止烤黍。本例中,信號(hào)發(fā)送了一個(gè)next事件來表示登錄是否成功傻盟,隨后是一個(gè)complete事件速蕊。
? ? ? 這個(gè)block的返回值是一個(gè)RACDisposable對(duì)象,它允許你在一個(gè)訂閱被取消時(shí)執(zhí)行一些清理工作娘赴。當(dāng)前的信號(hào)不需要執(zhí)行清理操作规哲,所以返回nil就可以了。
? ? ? ? - (RACSignal*)signInSignal {
? ? ? ? ? ? ? ?return[RACSignalcreateSignal:^RACDisposable*(idsubscriber){
? ? ? [self.signInService ? signInWithUsername:self.usernameTextField.text password:self.passwordTextField.text
complete:^(BOOLsuccess){
? ? ? ? ?[subscribersendNext:@(success)];
? ? ? ? ? [subscribersendCompleted];
? ? ? ? ?}];
? ? ? ? ?returnnil;
? ? ?}];
}
二诽表、使用RAC宏
? ? ? ?RAC宏允許直接把信號(hào)的輸出應(yīng)用到對(duì)象的屬性上唉锌。RAC宏有兩個(gè)參數(shù),第一個(gè)是需要設(shè)置屬性值的對(duì)象竿奏,第二個(gè)是屬性名袄简。每次信號(hào)產(chǎn)生一個(gè)next事件,傳遞過來的值都會(huì)應(yīng)用到該屬性上泛啸。
? ? ? ? RAC(self.passwordTextField.backgroundColor) = [validPassword Signalmap:^id(NSNumber*passwordValid) {
? ? ? ? ? ? ? ? NSLog(@"%d",[passwordValidboolValue]);
? ? ? ?return[passwordValid boolValue]?[UIColor clearColor]:[UIColor yellowColor];
? ? ? ?}];
? ? ? ?RAC(self.usernameTextField.backgroundColor) = [validUsername Signalmap:^id(NSNumber*usernameValid) {
? ? ? ? ? ? ? ? ? NSLog(@"%d",[usernameValid boolValue]);
? ? ? ?return[usernameValid boolValue]?[UIColor clearColor]:[UIColor yellowColor];
? ? ?}];
三绿语、信號(hào)聚合
? ? ? ?使用combineLatest:reduce:方法把幾個(gè)信號(hào)RACSignal產(chǎn)生的最新的值聚合在一起,并生成一個(gè)新的信號(hào)候址。每次這兩個(gè)源信號(hào)的任何一個(gè)產(chǎn)生新值時(shí)吕粹,reduce block都會(huì)執(zhí)行,block的返回值會(huì)發(fā)給下一個(gè)信號(hào)岗仑。
? ? ? ? ? ? RACSignal *signUpActiveSignal = [RACSignalcombineLatest:@[validUsernameSignal,validPasswordSignal] ? ? ? ?reduce:^id(NSNumber*usernameValid,NSNumber*passwordValid){
? ? ? ? ? ? ?return@([usernameValidboolValue]&&[passwordValid boolValue]);
? ? ? ? ? ? }];
? ? ? ? ? ? [signUpActiveSignal subscribeNext:^(NSNumber*signupActive) {
? ? ? ? ? ? self.signInButton.enabled= [signupActive boolValue];
}];
ReactiveCocoa的核心就是信號(hào)匹耕,而它不過就是事件流,ReactiveCocoa的主旨是讓你的代碼更簡(jiǎn)潔易懂!赔蒲!