此文章是針對ReactiveCocoa的學(xué)習(xí)總結(jié)整理,該文是第三篇。我們這篇主要講解一下RACCommand以及RAC替換UIKit的典型例子。未閱讀前兩篇的童鞋,吶,給你傳送門。
- ReactiveCocoa學(xué)習(xí)筆記整理(一)
-
ReactiveCocoa學(xué)習(xí)筆記整理(二)
好的,廢話不多說,讓我們馬上開始~
五. RACCommand的基本簡介跟使用
1. RACCommand簡介以及使用
RACCommand是RAC中用于處理事件的類,我們可以把事件如何處理,事件中的數(shù)據(jù)如何傳遞,包裝到這個類中。使用這個類可以很方便的監(jiān)控事件的執(zhí)行過程。RACCommand的使用步驟可以總結(jié)為以下三點:
- 創(chuàng)建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
- 在signalBlock中,創(chuàng)建RACSignal,并且作為signalBlock的返回值
-
執(zhí)行命令 -(RACSignal * )execute:(id)input
在RAC的開發(fā)中,我們通常會把網(wǎng)絡(luò)請求封裝到RACCommand,直接執(zhí)行某個RACCommand就能發(fā)送請求。然后當(dāng)RACCommand內(nèi)部請求到數(shù)據(jù)的時候,需要把請求的數(shù)據(jù)傳遞給外界,這時候就需要通過signalBlock返回的信號傳遞了。
那么我們?nèi)绾文玫絉ACCommand中返回信號發(fā)出的數(shù)據(jù)?
- RACCommand有個執(zhí)行信號源executionSignals,這個是signal of signals(信號的信號),意思是信號發(fā)出的數(shù)據(jù)是信號,不是普通的類型。
- 訂閱executionSignals就能拿到RACCommand中返回的信號,然后訂閱signalBlock返回的信號,就能獲取發(fā)出的值。
在RACCommand的使用過程中,我們及其要注意以下的幾點事項:
- signalBlock必須要返回一個信號,不能傳nil
- 如果不想要傳遞信號,直接創(chuàng)建空的信號[RACSignal empty]
- RACCommand中信號如果數(shù)據(jù)傳遞完,必須調(diào)用[subscriber sendCompleted],這時命令才會執(zhí)行完畢,否則永遠處于執(zhí)行中
-
RACCommand需要被強引用,否則接收不到RACCommand中的信號,因此RACCommand中的信號是延遲發(fā)送的
好了,大致了解了RACCommand的基本概念以及使用步驟之后,我們通過簡單的小實例來看一下RACCommand怎樣使用,接下來,我們模擬一下監(jiān)聽按鈕點擊,發(fā)送網(wǎng)絡(luò)請求的過程,請看代碼:
// 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 *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"請求數(shù)據(jù)"];
// 注意:數(shù)據(jù)傳遞完,最好調(diào)用sendCompleted,這時命令才執(zhí)行完畢。
[subscriber sendCompleted];
return nil;
}];
}];
// 強引用命令,不要被銷毀,否則接收不到數(shù)據(jù)
_conmmand = command;
// 3.訂閱RACCommand中的信號
[command.executionSignals subscribeNext:^(id x) {
[x subscribeNext:^(id x) {
NSLog(@"executionSignals:%@",x);
}];
}];
// RAC高級用法
// switchToLatest:用于signal of signals,獲取signal of signals發(fā)出的最新信號,也就是可以直接拿到RACCommand中的信號
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"executionSignals.switchToLatest:%@",x);
}];
// 4.監(jiān)聽命令是否執(zhí)行完畢,默認會來一次,可以直接跳過,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];
// 輸出
// 執(zhí)行命令
// 正在執(zhí)行
// executionSignals:請求數(shù)據(jù)
// executionSignals.switchToLatest:請求數(shù)據(jù)
// 執(zhí)行完成
上述代碼就是使用RACCommand模擬的點擊按鈕進行網(wǎng)絡(luò)請求的過程,可以看出,RACCommand可以很方便的處理事件以及事件中的數(shù)據(jù)傳遞。
2.RACMulticastConnection的使用
講到了RACCommand,那么必不可少的有按鈕的多次點擊導(dǎo)致多次網(wǎng)絡(luò)請求的問題。RACMulticastConnection用于當(dāng)一個信號,被多次訂閱時,為了保證創(chuàng)建信號時,避免多次調(diào)用創(chuàng)建信號中的block,造成副作用,可以使用這個類處理。首先,我們看一下RACMulticastConnection的使用步驟:
- 創(chuàng)建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
- 創(chuàng)建連接 RACMulticastConnection *connect = [signal publish];
- 訂閱信號,注意:訂閱的不在是之前的信號,而是連接的信號。 [connect.signal subscribeNext:nextBlock]
- 連接 [connect connect]
然后我們看一下RACMulticastConnection的底層實現(xiàn)原理:
- 創(chuàng)建connect,connect.sourceSignal -> RACSignal(原始信號) connect.signal -> RACSubject
- 訂閱connect.signal,會調(diào)用RACSubject的subscribeNext,創(chuàng)建訂閱者,而且把訂閱者保存起來,不會執(zhí)行block
- [connect connect]內(nèi)部會訂閱RACSignal(原始信號),并且訂閱者是RACSubject
訂閱原始信號,就會調(diào)用原始信號中的didSubscribe
didSubscribe,拿到訂閱者調(diào)用sendNext,其實是調(diào)用RACSubject的sendNext - RACSubject的sendNext,會遍歷RACSubject所有訂閱者發(fā)送信號
因為剛剛第二步,都是在訂閱RACSubject,因此會拿到第二步所有的訂閱者,調(diào)用他們的nextBlock
最后,我們通過簡單的小需求來實際使用一下。假設(shè)在一個信號中發(fā)送請求,每次訂閱一次都會發(fā)送請求,這樣就會導(dǎo)致多次請求。我們需要使用RACMulticastConnection解決這個問題。
// 1.創(chuàng)建請求信號
RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"aSignal發(fā)送請求");
return nil;
}];
// 2.訂閱信號
[aSignal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 2.訂閱信號
[aSignal subscribeNext:^(id x) {
NSLog(@"接收數(shù)據(jù)");
}];
// 3.運行結(jié)果,會執(zhí)行兩遍發(fā)送請求,也就是每次訂閱都會發(fā)送一次請求
// RACMulticastConnection:解決重復(fù)請求問題
// 1.創(chuàng)建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"signal發(fā)送請求");
[subscriber sendNext:@1];
return nil;
}];
// 2.創(chuàng)建連接
RACMulticastConnection *connect = [signal publish];
// 3.訂閱信號,
// 注意:訂閱信號,也不能激活信號,只是保存訂閱者到數(shù)組,必須通過連接,當(dāng)調(diào)用連接,就會一次性調(diào)用所有訂閱者的sendNext:
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者一信號");
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"訂閱者二信號");
}];
// 4.連接,激活信號
[connect connect];
//輸出
//aSignal發(fā)送請求
//aSignal發(fā)送請求
//signal發(fā)送請求
//訂閱者一信號
//訂閱者二信號
通過以上的代碼,可以明確的看出, aSignal被執(zhí)行的兩次,雖然有兩個訂閱者 ,但其實只要執(zhí)行一次就可以。使用RACMulticastConnection我們解決了這個問題。
截止此文,RAC的筆記就先到這吧,其實RAC還有很多高階用法以及更大的發(fā)揮空間,剩下的就由你們自己去慢慢發(fā)掘吧。