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