ReactiveCocoa 可以說是結(jié)合了函數(shù)式編程和響應(yīng)式編程的框架,也可稱其為函數(shù)響應(yīng)式編程(FRP)框架,強(qiáng)調(diào)一點(diǎn),RAC雖然最大的優(yōu)點(diǎn)是提供了一個(gè)單一的、統(tǒng)一的方法去處理異步的行為,包括delegate方法,blocks回調(diào),target-action機(jī)制,notifications和KVO.但是不要簡單的只是單純的認(rèn)為他僅僅就是減少代碼復(fù)雜度,更好的配合MVVM而已,小伙子,這樣你就小看它了。
我們提供的服務(wù)有:成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、靖安ssl等。為1000多家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的靖安網(wǎng)站制作公司
我知道這么多,懂不懂用就是你的事
使用ReactiveCocoa實(shí)現(xiàn)iOS平臺響應(yīng)式編程
ReactiveCocoa和響應(yīng)式編程
在說ReactiveCocoa之前,先要介紹一下FRP(Functional Reactive Programming,響應(yīng)式編程),在維基百科中有這樣一個(gè)例子介紹:
在命令式編程環(huán)境中,a = b + c 表示將表達(dá)式的結(jié)果賦給a,而之后改變b或c的值不會(huì)影響a。但在響應(yīng)式編程中,a的值會(huì)隨著b或c的更新而更新。
Excel就是響應(yīng)式編程的一個(gè)例子。單元格可以包含字面值或類似”=B1+C1″的公式,而包含公式的單元格的值會(huì)依據(jù)其他單元格的值的變化而變化 。
而ReactiveCocoa簡稱RAC,就是基于響應(yīng)式編程思想的Objective-C實(shí)踐,它是Github的一個(gè)開源項(xiàng)目,你可以在這里找到它。
關(guān)于FRP和ReactiveCocoa可以去看leezhong的這篇blog,圖文并茂,講的很好。
ReactiveCocoa框架概覽
先來看一下leezhong再博文中提到的比喻,讓你對有個(gè)ReactiveCocoa很好的理解:
可以把信號想象成水龍頭,只不過里面不是水,而是玻璃球(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)。也可以把多
1.ReactiveCocoa
ReactiveCocoa(簡稱為RAC),是由Github開源的一個(gè)應(yīng)用于iOS和OS開發(fā)的新框架,Cocoa是蘋果整套框架的簡稱,因此很多蘋果框架喜歡以Cocoa結(jié)尾。
2.ReactiveCocoa作用
在我們iOS開發(fā)過程中,經(jīng)常會(huì)響應(yīng)某些事件來處理某些業(yè)務(wù)邏輯,例如按鈕的點(diǎn)擊,上下拉刷新,網(wǎng)絡(luò)請求,屬性的變化(通過KVO)或者用戶位置的變化(通過CoreLocation)。但是這些事件都用不同的方式來處理,比如action、delegate、KVO、callback等。
其實(shí)這些事件,都可以通過RAC處理,ReactiveCocoa為事件提供了很多處理方法,而且利用RAC處理事件很方便,可以把要處理的事情,和監(jiān)聽的事情的代碼放在一起,這樣非常方便我們管理,就不需要跳到對應(yīng)的方法里。非常符合我們開發(fā)中高聚合,低耦合的思想。
3.編程思想
在開發(fā)中我們也不能太依賴于某個(gè)框架,否則這個(gè)框架不更新了,導(dǎo)致項(xiàng)目后期沒辦法維護(hù),比如之前Facebook提供的Three20框架,在當(dāng)時(shí)也是神器,但是后來不更新了,也就沒什么人用了。因此我感覺學(xué)習(xí)一個(gè)框架,還是有必要了解它的編程思想。
先簡單介紹下目前咱們已知的編程思想。
3.1 面向過程:處理事情以過程為核心,一步一步的實(shí)現(xiàn)。
3.2 面向?qū)ο螅喝f物皆對象
3.3 鏈?zhǔn)骄幊趟枷耄菏菍⒍鄠€(gè)操作(多行代碼)通過點(diǎn)號(.)鏈接在一起成為一句代碼,使代碼可讀性好。a(1).b(2).c(3)
鏈?zhǔn)骄幊烫攸c(diǎn):方法的返回值是block,block必須有返回值(本身對象),block參數(shù)(需要操作的值)
代表:masonry框架。
模仿masonry,寫一個(gè)加法計(jì)算器,練習(xí)鏈?zhǔn)骄幊趟枷搿?/p>
Snip20150925_2.png
Snip20150925_1.png
Paste_Image.png
3.4 響應(yīng)式編程思想:不需要考慮調(diào)用順序,只需要知道考慮結(jié)果,類似于蝴蝶效應(yīng),產(chǎn)生一個(gè)事件,會(huì)影響很多東西,這些事件像流一樣的傳播出去,然后影響結(jié)果,借用面向?qū)ο蟮囊痪湓?,萬物皆是流。
代表:KVO運(yùn)用。
3.5 函數(shù)式編程思想:是把操作盡量寫成一系列嵌套的函數(shù)或者方法調(diào)用。
函數(shù)式編程特點(diǎn):每個(gè)方法必須有返回值(本身對象),把函數(shù)或者Block當(dāng)做參數(shù),block參數(shù)(需要操作的值)block返回值(操作結(jié)果)
代表:ReactiveCocoa。
用函數(shù)式編程實(shí)現(xiàn),寫一個(gè)加法計(jì)算器,并且加法計(jì)算器自帶判斷是否等于某個(gè)值.
Paste_Image.png
Paste_Image.png
4.ReactiveCocoa編程思想
ReactiveCocoa結(jié)合了幾種編程風(fēng)格:
函數(shù)式編程(Functional Programming)
響應(yīng)式編程(Reactive Programming)
所以,你可能聽說過ReactiveCocoa被描述為函數(shù)響應(yīng)式編程(FRP)框架。
以后使用RAC解決問題,就不需要考慮調(diào)用順序,直接考慮結(jié)果,把每一次操作都寫成一系列嵌套的方法中,使代碼高聚合,方便管理。
5.如何導(dǎo)入ReactiveCocoa框架
通常都會(huì)使用CocoaPods(用于管理第三方框架的插件)幫助我們導(dǎo)入。
PS:CocoaPods教程
注意:
podfile如果只描述pod 'ReactiveCocoa', '~ 4.0.2-alpha-1',會(huì)導(dǎo)入不成功。
Snip20150926_1.png
報(bào)錯(cuò)提示信息
Snip20150926_2.png
需要在podfile加上use_frameworks,重新pod install 才能導(dǎo)入成功。
Snip20150926_3.png
6.ReactiveCocoa常見類。
學(xué)習(xí)框架首要之處:個(gè)人認(rèn)為先要搞清楚框架中常用的類,在RAC中最核心的類RACSiganl,搞定這個(gè)類就能用ReactiveCocoa開發(fā)了。
6.1RACSiganl:信號類,一般表示將來有數(shù)據(jù)傳遞,只要有數(shù)據(jù)改變,信號內(nèi)部接收到數(shù)據(jù),就會(huì)馬上發(fā)出數(shù)據(jù)。
注意:
信號類(RACSiganl),只是表示當(dāng)數(shù)據(jù)改變時(shí),信號內(nèi)部會(huì)發(fā)出數(shù)據(jù),它本身不具備發(fā)送信號的能力,而是交給內(nèi)部一個(gè)訂閱者去發(fā)出。
默認(rèn)一個(gè)信號都是冷信號,也就是值改變了,也不會(huì)觸發(fā),只有訂閱了這個(gè)信號,這個(gè)信號才會(huì)變?yōu)闊嵝盘?,值改變了才?huì)觸發(fā)。
如何訂閱信號:調(diào)用信號RACSignal的subscribeNext就能訂閱。
RACSiganl簡單使用:
// RACSignal使用步驟:
// 1.創(chuàng)建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(idRACSubscriber subscriber))didSubscribe
// 2.訂閱信號,才會(huì)激活信號. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.發(fā)送信號 - (void)sendNext:(id)value
// RACSignal底層實(shí)現(xiàn):
// 1.創(chuàng)建信號,首先把didSubscribe保存到信號中,還不會(huì)觸發(fā)。
// 2.當(dāng)信號被訂閱,也就是調(diào)用signal的subscribeNext:nextBlock
// 2.2 subscribeNext內(nèi)部會(huì)創(chuàng)建訂閱者subscriber,并且把nextBlock保存到subscriber中。
// 2.1 subscribeNext內(nèi)部會(huì)調(diào)用siganl的didSubscribe
// 3.siganl的didSubscribe中調(diào)用[subscriber sendNext:@1];
// 3.1 sendNext底層其實(shí)就是執(zhí)行subscriber的nextBlock
// 1.創(chuàng)建信號
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(idRACSubscriber subscriber) {
// block調(diào)用時(shí)刻:每當(dāng)有訂閱者訂閱信號,就會(huì)調(diào)用block。
// 2.發(fā)送信號
[subscriber sendNext:@1];
// 如果不在發(fā)送數(shù)據(jù),最好發(fā)送信號完成,內(nèi)部會(huì)自動(dòng)調(diào)用[RACDisposable disposable]取消訂閱信號。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// block調(diào)用時(shí)刻:當(dāng)信號發(fā)送完成或者發(fā)送錯(cuò)誤,就會(huì)自動(dòng)執(zhí)行這個(gè)block,取消訂閱信號。
// 執(zhí)行完Block后,當(dāng)前信號就不在被訂閱了。
NSLog(@"信號被銷毀");
}];
}];
// 3.訂閱信號,才會(huì)激活信號.
[siganl subscribeNext:^(id x) {
// block調(diào)用時(shí)刻:每當(dāng)有信號發(fā)出數(shù)據(jù),就會(huì)調(diào)用block.
NSLog(@"接收到數(shù)據(jù):%@",x);
}];
6.2 RACSubscriber:表示訂閱者的意思,用于發(fā)送信號,這是一個(gè)協(xié)議,不是一個(gè)類,只要遵守這個(gè)協(xié)議,并且實(shí)現(xiàn)方法才能成為訂閱者。通過create創(chuàng)建的信號,都有一個(gè)訂閱者,幫助他發(fā)送數(shù)據(jù)。
6.3 RACDisposable:用于取消訂閱或者清理資源,當(dāng)信號發(fā)送完成或者發(fā)送錯(cuò)誤的時(shí)候,就會(huì)自動(dòng)觸發(fā)它。
使用場景:不想監(jiān)聽某個(gè)信號時(shí),可以通過它主動(dòng)取消訂閱信號。
6.4 RACSubject:RACSubject:信號提供者,自己可以充當(dāng)信號,又能發(fā)送信號。
使用場景:通常用來代替代理,有了它,就不必要定義代理了。
6.5 RACReplaySubject:重復(fù)提供信號者,RACSubject的子類。
使用場景:如果一個(gè)信號每被訂閱一次,就需要把之前的值重復(fù)發(fā)送一遍,使用重復(fù)提供信號類。
RACSubject和RACReplaySubject簡單使用:
// RACSubject使用步驟
// 1.創(chuàng)建信號 [RACSubject subject],跟RACSiganl不一樣,創(chuàng)建信號時(shí)沒有block。
// 2.訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.發(fā)送信號 sendNext:(id)value
// RACSubject:底層實(shí)現(xiàn)和RACSignal不一樣。
// 1.調(diào)用subscribeNext訂閱信號,只是把訂閱者保存起來,并且訂閱者的nextBlock已經(jīng)賦值了。
// 2.調(diào)用sendNext發(fā)送信號,遍歷剛剛保存的所有訂閱者,一個(gè)一個(gè)調(diào)用訂閱者的nextBlock。
// 1.創(chuàng)建信號
RACSubject *subject = [RACSubject subject];
// 2.訂閱信號
[subject subscribeNext:^(id x) {
// block調(diào)用時(shí)刻:當(dāng)信號發(fā)出新值,就會(huì)調(diào)用.
NSLog(@"第一個(gè)訂閱者%@",x);
}];
[subject subscribeNext:^(id x) {
// block調(diào)用時(shí)刻:當(dāng)信號發(fā)出新值,就會(huì)調(diào)用.
NSLog(@"第二個(gè)訂閱者%@",x);
}];
// 3.發(fā)送信號
[subject sendNext:@"1"];
// RACReplaySubject使用步驟:
// 1.創(chuàng)建信號 [RACSubject subject],跟RACSiganl不一樣,創(chuàng)建信號時(shí)沒有block。
// 2.可以先訂閱信號,也可以先發(fā)送信號。
// 2.1 訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 2.2 發(fā)送信號 sendNext:(id)value
// RACReplaySubject:底層實(shí)現(xiàn)和RACSubject不一樣。
// 1.調(diào)用sendNext發(fā)送信號,把值保存起來,然后遍歷剛剛保存的所有訂閱者,一個(gè)一個(gè)調(diào)用訂閱者的nextBlock。
// 2.調(diào)用subscribeNext訂閱信號,遍歷保存的所有值,一個(gè)一個(gè)調(diào)用訂閱者的nextBlock
// 如果想當(dāng)一個(gè)信號被訂閱,就重復(fù)播放之前所有值,需要先發(fā)送信號,在訂閱信號。
// 也就是先保存值,在訂閱值。
// 1.創(chuàng)建信號
RACReplaySubject *replaySubject = [RACReplaySubject subject];
// 2.發(fā)送信號
[replaySubject sendNext:@1];
[replaySubject sendNext:@2];
// 3.訂閱信號
[replaySubject subscribeNext:^(id x) {
NSLog(@"第一個(gè)訂閱者接收到的數(shù)據(jù)%@",x);
}];
// 訂閱信號
[replaySubject subscribeNext:^(id x) {
NSLog(@"第二個(gè)訂閱者接收到的數(shù)據(jù)%@",x);
}];
RACSubject替換代理// 1.創(chuàng)建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"執(zhí)行命令");
// 創(chuàng)建空信號,必須返回信號
// return [RACSignal empty];
// 2.創(chuàng)建信號,用來傳遞數(shù)據(jù)
return [RACSignal createSignal:^RACDisposable *(idRACSubscriber subscriber) {
[subscriber sendNext:@"請求數(shù)據(jù)"];
// 注意:數(shù)據(jù)傳遞完,最好調(diào)用sendCompleted,這時(shí)命令才執(zhí)行完畢。
[subscriber sendCompleted];
return nil;
}];
}];
// 強(qiáng)引用命令,不要被銷毀,否則接收不到數(shù)據(jù)
_conmmand = command;
// 3.訂閱RACCommand中的信號
[command.executionSignals subscribeNext:^(id x) {
[x subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}];
// RAC高級用法
// switchToLatest:用于signal of signals,獲取signal of signals發(fā)出的最新信號,也就是可以直接拿到RACCommand中的信號
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 4.監(jiān)聽命令是否執(zhí)行完畢,默認(rèn)會(huì)來一次,可以直接跳過,skip表示跳過第一次信號。
[[command.executing skip:1] subscribeNext:^(id x) {
if ([x boolValue] == YES) {
// 正在執(zhí)行
NSLog(@"正在執(zhí)行");
}else{
// 執(zhí)行完成
NSLog(@"執(zhí)行完成");
}
}];
// 5.執(zhí)行命令
[self.conmmand execute:@1];
6.9RACMulticastConnection:用于當(dāng)一個(gè)信號,被多次訂閱時(shí),為了保證創(chuàng)建信號時(shí),避免多次調(diào)用創(chuàng)建信號中的block,造成副作用,可以使用這個(gè)類處理。
使用注意:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創(chuàng)建.
RACMulticastConnection簡單使用:
// RACMulticastConnection使用步驟:
// 1.創(chuàng)建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(idRACSubscriber))didSubscribe
// 2.創(chuàng)建連接 RACMulticastConnection *connect = [signal publish];
// 3.訂閱信號,注意:訂閱的不在是之前的信號,而是連接的信號。 [connect.signal subscribeNext:nextBlock]
// 4.連接 [connect connect]
// RACMulticastConnection底層原理:
// 1.創(chuàng)建connect,connect.sourceSignal - RACSignal(原始信號) connect.signal - RACSubject
// 2.訂閱connect.signal,會(huì)調(diào)用RACSubject的subscribeNext,創(chuàng)建訂閱者,而且把訂閱者保存起來,不會(huì)執(zhí)行block。
// 3.[connect connect]內(nèi)部會(huì)訂閱RACSignal(原始信號),并且訂閱者是RACSubject
// 3.1.訂閱原始信號,就會(huì)調(diào)用原始信號中的didSubscribe
// 3.2 didSubscribe,拿到訂閱者調(diào)用sendNext,其實(shí)是調(diào)用RACSubject的sendNext
// 4.RACSubject的sendNext,會(huì)遍歷RACSubject所有訂閱者發(fā)送信號。
// 4.1 因?yàn)閯倓偟诙?,都是在訂閱RACSubject,因此會(huì)拿到第二步所有的訂閱者,調(diào)用他們的nextBlock
// 需求:假設(shè)在一個(gè)信號中發(fā)送請求,每次訂閱一次都會(huì)發(fā)送請求,這樣就會(huì)導(dǎo)致多次請求。
// 解決:使用RACMulticastConnection就能解決.
// 1.創(chuàng)建請求信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(idRACSubscriber subscriber) {
NSLog(@"發(fā)送請求");
return nil;
}];
// 2.訂閱信號
[signal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 2.訂閱信號
[signal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 3.運(yùn)行結(jié)果,會(huì)執(zhí)行兩遍發(fā)送請求,也就是每次訂閱都會(huì)發(fā)送一次請求
// RACMulticastConnection:解決重復(fù)請求問題
// 1.創(chuàng)建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(idRACSubscriber subscriber) {
NSLog(@"發(fā)送請求");
[subscriber sendNext:@1];
return nil;
}];
// 2.創(chuàng)建連接
RACMulticastConnection *connect = [signal publish];
// 3.訂閱信號,
// 注意:訂閱信號,也不能激活信號,只是保存訂閱者到數(shù)組,必須通過連接,當(dāng)調(diào)用連接,就會(huì)一次性調(diào)用所有訂閱者的sendNext:
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者一信號");
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者二信號");
}];
// 4.連接,激活信號
[connect connect];
6.10 RACScheduler:RAC中的隊(duì)列,用GCD封裝的。
6.11 RACUnit :表?stream不包含有意義的值,也就是看到這個(gè),可以直接理解為nil.
6.12 RACEvent: 把數(shù)據(jù)包裝成信號事件(signal event)。它主要通過RACSignal的-materialize來使用,然并卵。
7.ReactiveCocoa開發(fā)中常見用法。
7.1 代替代理:
rac_signalForSelector:用于替代代理。
7.2 代替KVO :
rac_valuesAndChangesForKeyPath:用于監(jiān)聽某個(gè)對象的屬性改變。
7.3 監(jiān)聽事件:
rac_signalForControlEvents:用于監(jiān)聽某個(gè)事件。
7.4 代替通知:
rac_addObserverForName:用于監(jiān)聽某個(gè)通知。
7.5 監(jiān)聽文本框文字改變:
rac_textSignal:只要文本框發(fā)出改變就會(huì)發(fā)出這個(gè)信號。
7.6 處理當(dāng)界面有多次請求時(shí),需要都獲取到數(shù)據(jù)時(shí),才能展示界面
rac_liftSelector:withSignalsFromArray:Signals:當(dāng)傳入的Signals(信號數(shù)組),每一個(gè)signal都至少sendNext過一次,就會(huì)去觸發(fā)第一個(gè)selector參數(shù)的方法。
使用注意:幾個(gè)信號,參數(shù)一的方法就幾個(gè)參數(shù),每個(gè)參數(shù)對應(yīng)信號發(fā)出的數(shù)據(jù)。
7.7 代碼演示
// 1.代替代理
// 需求:自定義redView,監(jiān)聽紅色view中按鈕點(diǎn)擊
// 之前都是需要通過代理監(jiān)聽,給紅色View添加一個(gè)代理屬性,點(diǎn)擊按鈕的時(shí)候,通知代理做事情
// rac_signalForSelector:把調(diào)用某個(gè)對象的方法的信息轉(zhuǎn)換成信號,就要調(diào)用這個(gè)方法,就會(huì)發(fā)送信號。
// 這里表示只要redV調(diào)用btnClick:,就會(huì)發(fā)出信號,訂閱就好了。
[[redV rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"點(diǎn)擊紅色按鈕");
}];
// 2.KVO
// 把監(jiān)聽redV的center屬性改變轉(zhuǎn)換成信號,只要值改變就會(huì)發(fā)送信號
// observer:可以傳入nil
[[redV rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.監(jiān)聽事件
// 把按鈕點(diǎn)擊事件轉(zhuǎn)換為信號,點(diǎn)擊按鈕,就會(huì)發(fā)送信號
[[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按鈕被點(diǎn)擊了");
}];
文章名稱:ios開發(fā)響應(yīng)式編程,ios 程序開發(fā)
文章起源:http://sd-ha.com/article36/hoossg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、網(wǎng)站收錄、網(wǎng)站設(shè)計(jì)、微信小程序、建站公司、App設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)