此文章是針對(duì)ReactiveCocoa的學(xué)習(xí)總結(jié)整理,該文是第三篇。我們這篇主要講解一下RACCommand以及RAC替換UIKit的典型例子柒室。未閱讀前兩篇的童鞋,吶喇完,給你傳送門伦泥。
- ReactiveCocoa學(xué)習(xí)筆記整理(一)
-
ReactiveCocoa學(xué)習(xí)筆記整理(二)
好的,廢話不多說锦溪,讓我們馬上開始~
五. RACCommand的基本簡(jiǎn)介跟使用
1. RACCommand簡(jiǎn)介以及使用
RACCommand是RAC中用于處理事件的類不脯,我們可以把事件如何處理,事件中的數(shù)據(jù)如何傳遞,包裝到這個(gè)類中刻诊。使用這個(gè)類可以很方便的監(jiān)控事件的執(zhí)行過程防楷。RACCommand的使用步驟可以總結(jié)為以下三點(diǎn):
- 創(chuàng)建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
- 在signalBlock中,創(chuàng)建RACSignal则涯,并且作為signalBlock的返回值
-
執(zhí)行命令 -(RACSignal * )execute:(id)input
在RAC的開發(fā)中复局,我們通常會(huì)把網(wǎng)絡(luò)請(qǐng)求封裝到RACCommand,直接執(zhí)行某個(gè)RACCommand就能發(fā)送請(qǐng)求粟判。然后當(dāng)RACCommand內(nèi)部請(qǐng)求到數(shù)據(jù)的時(shí)候亿昏,需要把請(qǐng)求的數(shù)據(jù)傳遞給外界,這時(shí)候就需要通過signalBlock返回的信號(hào)傳遞了档礁。
那么我們?nèi)绾文玫絉ACCommand中返回信號(hào)發(fā)出的數(shù)據(jù)角钩?
- RACCommand有個(gè)執(zhí)行信號(hào)源executionSignals,這個(gè)是signal of signals(信號(hào)的信號(hào)),意思是信號(hào)發(fā)出的數(shù)據(jù)是信號(hào),不是普通的類型递礼。
- 訂閱executionSignals就能拿到RACCommand中返回的信號(hào)惨险,然后訂閱signalBlock返回的信號(hào),就能獲取發(fā)出的值脊髓。
在RACCommand的使用過程中辫愉,我們及其要注意以下的幾點(diǎn)事項(xiàng):
- signalBlock必須要返回一個(gè)信號(hào),不能傳nil
- 如果不想要傳遞信號(hào)将硝,直接創(chuàng)建空的信號(hào)[RACSignal empty]
- RACCommand中信號(hào)如果數(shù)據(jù)傳遞完恭朗,必須調(diào)用[subscriber sendCompleted],這時(shí)命令才會(huì)執(zhí)行完畢袋哼,否則永遠(yuǎn)處于執(zhí)行中
-
RACCommand需要被強(qiáng)引用冀墨,否則接收不到RACCommand中的信號(hào),因此RACCommand中的信號(hào)是延遲發(fā)送的
好了涛贯,大致了解了RACCommand的基本概念以及使用步驟之后诽嘉,我們通過簡(jiǎn)單的小實(shí)例來看一下RACCommand怎樣使用,接下來弟翘,我們模擬一下監(jiān)聽按鈕點(diǎn)擊虫腋,發(fā)送網(wǎng)絡(luò)請(qǐng)求的過程,請(qǐng)看代碼:
// 1.創(chuàng)建命令
RACCommand *command=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"執(zhí)行命令");
// 創(chuàng)建空信號(hào),必須返回信號(hào)
// return [RACSignal empty];
// 2.創(chuàng)建信號(hào),用來傳遞數(shù)據(jù)
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"請(qǐng)求數(shù)據(jù)"];
// 注意:數(shù)據(jù)傳遞完稀余,最好調(diào)用sendCompleted悦冀,這時(shí)命令才執(zhí)行完畢。
[subscriber sendCompleted];
return nil;
}];
}];
// 強(qiáng)引用命令睛琳,不要被銷毀盒蟆,否則接收不到數(shù)據(jù)
_conmmand = command;
// 3.訂閱RACCommand中的信號(hào)
[command.executionSignals subscribeNext:^(id x) {
[x subscribeNext:^(id x) {
NSLog(@"executionSignals:%@",x);
}];
}];
// RAC高級(jí)用法
// switchToLatest:用于signal of signals,獲取signal of signals發(fā)出的最新信號(hào),也就是可以直接拿到RACCommand中的信號(hào)
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"executionSignals.switchToLatest:%@",x);
}];
// 4.監(jiān)聽命令是否執(zhí)行完畢,默認(rèn)會(huì)來一次师骗,可以直接跳過历等,skip表示跳過第一次信號(hào)。
[[command.executing skip:1] subscribeNext:^(id x) {
if ([x boolValue] == YES) {
// 正在執(zhí)行
NSLog(@"正在執(zhí)行");
}else{
// 執(zhí)行完成
NSLog(@"執(zhí)行完成");
}
}];
// 5.執(zhí)行命令
[self.conmmand execute:@1];
// 輸出
// 執(zhí)行命令
// 正在執(zhí)行
// executionSignals:請(qǐng)求數(shù)據(jù)
// executionSignals.switchToLatest:請(qǐng)求數(shù)據(jù)
// 執(zhí)行完成
上述代碼就是使用RACCommand模擬的點(diǎn)擊按鈕進(jìn)行網(wǎng)絡(luò)請(qǐng)求的過程辟癌,可以看出寒屯,RACCommand可以很方便的處理事件以及事件中的數(shù)據(jù)傳遞。
2.RACMulticastConnection的使用
講到了RACCommand黍少,那么必不可少的有按鈕的多次點(diǎn)擊導(dǎo)致多次網(wǎng)絡(luò)請(qǐng)求的問題寡夹。RACMulticastConnection用于當(dāng)一個(gè)信號(hào),被多次訂閱時(shí)厂置,為了保證創(chuàng)建信號(hào)時(shí)菩掏,避免多次調(diào)用創(chuàng)建信號(hào)中的block,造成副作用昵济,可以使用這個(gè)類處理智绸。首先或颊,我們看一下RACMulticastConnection的使用步驟:
- 創(chuàng)建信號(hào) + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
- 創(chuàng)建連接 RACMulticastConnection *connect = [signal publish];
- 訂閱信號(hào),注意:訂閱的不在是之前的信號(hào),而是連接的信號(hào)传于。 [connect.signal subscribeNext:nextBlock]
- 連接 [connect connect]
然后我們看一下RACMulticastConnection的底層實(shí)現(xiàn)原理:
- 創(chuàng)建connect,connect.sourceSignal -> RACSignal(原始信號(hào)) connect.signal -> RACSubject
- 訂閱connect.signal醉顽,會(huì)調(diào)用RACSubject的subscribeNext沼溜,創(chuàng)建訂閱者,而且把訂閱者保存起來游添,不會(huì)執(zhí)行block
- [connect connect]內(nèi)部會(huì)訂閱RACSignal(原始信號(hào))系草,并且訂閱者是RACSubject
訂閱原始信號(hào),就會(huì)調(diào)用原始信號(hào)中的didSubscribe
didSubscribe唆涝,拿到訂閱者調(diào)用sendNext找都,其實(shí)是調(diào)用RACSubject的sendNext - RACSubject的sendNext,會(huì)遍歷RACSubject所有訂閱者發(fā)送信號(hào)
因?yàn)閯倓偟诙剑际窃谟嗛哛ACSubject廊酣,因此會(huì)拿到第二步所有的訂閱者能耻,調(diào)用他們的nextBlock
最后,我們通過簡(jiǎn)單的小需求來實(shí)際使用一下亡驰。假設(shè)在一個(gè)信號(hào)中發(fā)送請(qǐng)求晓猛,每次訂閱一次都會(huì)發(fā)送請(qǐng)求,這樣就會(huì)導(dǎo)致多次請(qǐng)求凡辱。我們需要使用RACMulticastConnection解決這個(gè)問題戒职。
// 1.創(chuàng)建請(qǐng)求信號(hào)
RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"aSignal發(fā)送請(qǐng)求");
return nil;
}];
// 2.訂閱信號(hào)
[aSignal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 2.訂閱信號(hào)
[aSignal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 3.運(yùn)行結(jié)果,會(huì)執(zhí)行兩遍發(fā)送請(qǐng)求透乾,也就是每次訂閱都會(huì)發(fā)送一次請(qǐng)求
// RACMulticastConnection:解決重復(fù)請(qǐng)求問題
// 1.創(chuàng)建信號(hào)
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"signal發(fā)送請(qǐng)求");
[subscriber sendNext:@1];
return nil;
}];
// 2.創(chuàng)建連接
RACMulticastConnection *connect = [signal publish];
// 3.訂閱信號(hào)洪燥,
// 注意:訂閱信號(hào),也不能激活信號(hào)乳乌,只是保存訂閱者到數(shù)組捧韵,必須通過連接,當(dāng)調(diào)用連接,就會(huì)一次性調(diào)用所有訂閱者的sendNext:
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者一信號(hào)");
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者二信號(hào)");
}];
// 4.連接,激活信號(hào)
[connect connect];
//輸出
//aSignal發(fā)送請(qǐng)求
//aSignal發(fā)送請(qǐng)求
//signal發(fā)送請(qǐng)求
//訂閱者一信號(hào)
//訂閱者二信號(hào)
通過以上的代碼钦扭,可以明確的看出纫版, aSignal被執(zhí)行的兩次,雖然有兩個(gè)訂閱者 客情,但其實(shí)只要執(zhí)行一次就可以其弊。使用RACMulticastConnection我們解決了這個(gè)問題。
截止此文膀斋,RAC的筆記就先到這吧梭伐,其實(shí)RAC還有很多高階用法以及更大的發(fā)揮空間,剩下的就由你們自己去慢慢發(fā)掘吧仰担。