iOS RAC學習之路(二)

前言

之前對RAC有了一個基本的認識,了解了它的作用,以及RAC的運行機制,我們知道只要是信號(RACSignal),我們就能對它進行一頓訂閱,然后執行觸發操作;接下來我們來學習一下RAC中常用的類以及一系列的用法。


RACSignal

這是一個信號類,表示一個信號源,只要有數據改變就會把數據包裝成信號傳遞出去,它本身不具備發送信號的能力,而是交給內部的一個訂閱者(RACSubscriber)去發出,然后當信號被訂閱之后,就會在其內部就創建一個訂閱者,所以在信號內部就可以發送信號了,之前也對RACSignal做了一個簡單的了解,下面學習一下更多的用法

  • 常用事件處理
  • Target-Action
 [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        //x==btn
        NSLog(@"%@",x);
        [self push];
 }];
  • Delegate
//因為訂閱信號是void返回類型的,所以只能代替void返回類型的delegate
[textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        //x==textField.text
        NSLog(@"%@",x);
}];
  • KVO
//直接用宏
[RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
        //x==新背景顏色
        NSLog(@"%@",x);
 }];
//也可以這樣
__weak typeof(self) weakSelf = self;
 [[self.view rac_valuesForKeyPath:@"backgroundColor" observer:weakSelf] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
 }];
  • 通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        //x==userInfo
        NSLog(@"%@",x);
 }];
  • 常用方法
  • flattenMapmap
    這是兩個映射方法,將源信號內容映射成新的內容,就像signal管道上的中間處理器,從這里走過的signal都會經過一段處理后,變成新的signal繼續傳輸。
//map,將輸出NSNumber的signal轉換成輸出NSString
RACSignal *mapSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        [subscriber sendNext:@(1)];
        return nil;
    }] map:^id _Nullable(id  _Nullable value) {

        return [NSString stringWithFormat:@"%@",value];
    }];
    [mapSignal subscribeNext:^(id  _Nullable x) {
        //NSString類型
        NSLog(@"x");
    }];
//flattenMap,將輸出NSNumber的signal轉換成輸出NSString
RACSignal *mapSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
        
    }] flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
        
        return [RACReturnSignal return:[NSString stringWithFormat:@"%@",value]];
    }];
    [mapSignal subscribeNext:^(id  _Nullable x) {
        //NSString類型
        NSLog(@"x");
    }];

兩者之間的區別就在于,map中Block返回轉換對象,flattenMap返回轉換對象的信號。一般信號發出的值不是信號,使用map;如果是信號則使用flattenMap,它可以處理信號中的信號。

  • merge:把多個信號合并成一個信號,只需訂閱這一個信號就相當于訂閱了多個信號,任何一個信號有新值的時候都會觸發調用。
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        return nil;
    }];
    RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(3)];
        return nil;
    }];
    RACSignal *mergeSignal = [RACSignal merge:@[signal1,signal2,signal3]];
    [mergeSignal subscribeNext:^(id  _Nullable x) {
        //分別輸出1,2,3
        NSLog(@"%@",x);
    }];
  • concat:將多個信號有順序的連接起來,按照順序接收信號,但是一定要之前的信號完成了才能發送下一個信號。
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        //發送信號完成,表示不再訂閱了,內部會自動調用[RACDisposable disposable]取消訂閱信號。
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(3)];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *concatSignal = [RACSignal concat:@[signal2,signal1,signal3]];
    [concatSignal subscribeNext:^(id  _Nullable x) {
        //分別輸出2,1,3
        NSLog(@"%@",x);
    }];
  • then:用于連接兩個信號,內部也是使用concat,當前一個信號完成之后才會連接then返回的信號,但是會忽略前一個信號,只會觸發下個信號。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendCompleted];
        return nil;
    }];
   RACSignal *thenSignal =  [signal1 then:^RACSignal * _Nonnull{
      return  [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
           [subscriber sendNext:@(2)];
           [subscriber sendCompleted];
           return nil;
       }];
   }];
    [thenSignal subscribeNext:^(id  _Nullable x) {
        //輸出2
        NSLog(@"%@",x);
    }];
  • zip:將對各信號壓縮成一個信號,只有當幾個信號同時sendNext的時候才會觸發壓縮流的next事件,其中每一個信號send的內容都是一一對應的。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        //不會覆蓋上一個信號
        [subscriber sendNext:@(3)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@(2)];
        return nil;
    }] ;
    RACSignal *zipSignal = [RACSignal zip:@[signal1,signal2]];
    [zipSignal subscribeNext:^(id  _Nullable x) {
        //輸出(1,2)
        NSLog(@"%@",x);
    }];
  • combineLatest:將多個信號組合起來,當其中每一個信號都sendNext之后,才會觸發組合的信號,其中每一個信號再次sendNext都會覆蓋之前的信號內容,返回的是一個RACTuple(元組,類似于NSArray)。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        //將覆蓋之前的信號,這就是跟zip的區別
        [subscriber sendNext:@(3)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        return nil;
    }];
   //如果其中一個信號不sendNext,則不會觸發組合信號
    RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] ];
    [combineSignal subscribeNext:^(id  _Nullable x) {
        //輸出(3,2)
        NSLog(@"%@",x);
    }];
  • rac_liftSelector: withSignalsFromArray::當信號組中每一個信號都至少一次sendNext之后,將觸發Selector方法,類似于combineLatest
    RACSubject *subject1 = [RACSubject subject];
    RACSubject *subject2 = [RACSubject subject];
    [[self rac_liftSelector:@selector(updateWithParameter1:parameter2:) withSignals:subject1,subject2, nil] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    [subject1 sendNext:@1];
    [subject2 sendNext:@2];
  • reduceEach:一般用于元組,把元組的值聚合成一個值。
RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] ];
    RACSignal *reduceSignal = [combineSignal reduceEach:^id (NSNumber *num1,NSNumber *num2){
        return @(num1.doubleValue+num2.doubleValue);
    }];
    [reduceSignal subscribeNext:^(id  _Nullable x) {
        //輸出3
        NSLog(@"%@",x);
    }];
//等同于+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock
//    RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] reduce:^id (NSNumber *num1,NSNumber *num2){
//        return @(num1.doubleValue+num2.doubleValue);
//    }];
  • filter:過濾信號,添加篩選條件,只有符合的才會觸發調用。
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@"3"];
        return nil;
    }];
    RACSignal *filterSignal = [signal1 filter:^BOOL(id  _Nullable value) {
        return [value isKindOfClass:[NSNumber class]];
    }];
    [filterSignal subscribeNext:^(id  _Nullable x) {
        //輸出1
        NSLog(@"%@",x);
    }];
    
    //數組的篩選
    RACSequence *sequence = [@[@(1),@(2),@"3"].rac_sequence filter:^BOOL(id  _Nullable value) {
        return [value isKindOfClass:[NSNumber class]];
    }];
    [sequence.signal subscribeNext:^(id  _Nullable x) {
        //輸出1,2
        NSLog(@"%@",x);
    }];
  • distinctUntilChanged:當前值跟上一次的值不同的時候,就會觸發調用,否則被忽略。
[textField.rac_textSignal.distinctUntilChanged subscribeNext:^(NSString * _Nullable x) {
        //變化時輸出變化之后的值
        NSLog(@"%@",x);
    }];
  • take:從第一個信號開始設置信號發送的有效的個數。
    RACSignal *signal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@(2)];
        return nil;
    }] take:1];
    
    [signal subscribeNext:^(id  _Nullable x) {
        //輸出1,因為take為1,所以有效的只有最開始的那一個,其他的忽略掉了
        NSLog(@"%@",x);
    }];
  • takeLast:從最后一個開始設置信號發送的有效個數,必須sendCompleted,不然不知道總共多少個信號。
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@(2)];
        [subscriber sendCompleted];
        return nil;
    }] takeLast:1] subscribeNext:^(id  _Nullable x) {
        //輸出2
        NSLog(@"%@",x);
    }];
  • takeUntil[signal1 takeUntil:signal2],當signal2已經sendNext或者sendCompleted,signal1就會失效。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        return nil;
    }];
    [[signal1 takeUntil:signal2] subscribeNext:^(id  _Nullable x) {
        //什么都不會輸出,因為signal2已經sendNext,所以signal1就會失效
        NSLog(@"%@",x);
    }];
  • skip:跳躍,從第一個發出的信號開始跳。
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@(2)];
        [subscriber sendNext:@(3)];
        return nil;
    }] skip:2] subscribeNext:^(id  _Nullable x) {
        //輸出3
        NSLog(@"%@",x);
    }];
  • doNext:在執行sendNext之前會執行這個。
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }] doNext:^(id  _Nullable x) {
        x = [NSString stringWithFormat:@"%@haha",x];
        //輸出1haha,在訂閱回調之前執行
        NSLog(@"%@",x);
    }] subscribeNext:^(id  _Nullable x) {
        //輸出1
        NSLog(@"%@",x);
    }];
  • timeout:在超過設定時間范圍之后讓信號報錯,且不能發送內容。
    RACSubject *subject = [RACSubject subject];
    [[subject timeout:3 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id  _Nullable x) {
        //只輸出1
        NSLog(@"%@",x);
    } error:^(NSError * _Nullable error) {
        //3秒之后輸出錯誤日志
        NSLog(@"%@",error);
    }];
    [subject sendNext:@1];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [subject sendNext:@2];
    });
  • interval:定時,每隔一定時間發出時間信號。
//RACScheduler:隊列
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
        //每隔一秒輸出當前時間
        NSLog(@"%@",x);
}];
  • delay:延時發送信號
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }] delay:3] subscribeNext:^(id  _Nullable x) {
        //3秒之后輸出1
        NSLog(@"%@",x);
    }];
  • retry:重試,只要失敗,就會重新執行創建信號中的block,直到成功。
    __block NSInteger i = 0;
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        i++;
        if (i > 10) {
            [subscriber sendNext:@(1)];
        }else{
            [subscriber sendError:nil];
        }
        return nil;
    }] retry] subscribeNext:^(id  _Nullable x) {
        //重試10次之后輸出1
        NSLog(@"%@",x);
    }error:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];
  • throttle:節流,當某個信號發送比較頻繁的時候,可以限制在一定之間內不接受信號,等過了這個時間再取最后發送的信號內容發出,類似于bufferWithTime:onScheduler:
    RACSubject *subject = [RACSubject subject];
// [subject bufferWithTime:1 onScheduler:[RACScheduler currentScheduler]];
    [[subject throttle:1] subscribeNext:^(id  _Nullable x) {
        //輸出3,拿到最后發出的內容3
        NSLog(@"%@",x);
    }];
    [subject sendNext:@1];
    [subject sendNext:@2];
    [subject sendNext:@3];
  • deliverOn:內容傳遞切換到指定線程中,副作用在原來線程中,把在創建信號時block中的代碼稱之為副作用。
  • subscribeOn:內容傳遞和副作用都會切換到指定線程中。

RACSubject

信號提供者,本身可以充當信號,又能發送信號,繼承自RACSignal,但是底層實現跟RACSignal有些不一樣,當訂閱信號的時候會創建訂閱者并保存訂閱響應Block,而發送信號的時候會遍歷訂閱者,然后分別調用nextBlock。它提供的API很少,但是經常使用,因為它繼承自RACSignal。這里順便來看一下方法 flattenswitchToLatest,這兩個都只能用來處理信號中的信號。

  • flatten:壓平信號中的信號,信號中的信號我們稱之為子信號,flatten可以拿到所有子信號發送的值。
RACSubject *subject = [RACSubject subject];
RACSubject *subSubject1 = [RACSubject subject];
RACSubject *subSubject2 = [RACSubject subject];
[subject subscribeNext:^(id  _Nullable x) {
    //分別輸出subSubject1,subSubject2,但是不能拿到其中的值
    NSLog(@"%@",x);
}];
[subject.flatten subscribeNext:^(id  _Nullable x) {
    //分別輸出1,2, flatten可以拿到所有子信號發送的值
    NSLog(@"%@",x);
}];
[subject sendNext:subSubject1];
[subject sendNext:subSubject2];
[subSubject1 sendNext:@1];
[subSubject2 sendNext:@2];
  • switchToLatest:與flatten相同,壓平信號中的信號,不同的是,在存在多個子信號時候只會拿到最新的子信號,然后輸出最新的子信號的值。
RACSubject *subject = [RACSubject subject];
RACSubject *subSubject1 = [RACSubject subject];
RACSubject *subSubject2 = [RACSubject subject];
[subject subscribeNext:^(id  _Nullable x) {
    //分別輸出subSubject1,subSubject2,但是不能拿到其中的值
    NSLog(@"%@",x);
}];
[subject.switchToLatest subscribeNext:^(id  _Nullable x) {
    //輸出2, switchToLatest只會拿到最新的子信號發送的值
    NSLog(@"%@",x);
}];
[subject sendNext:subSubject1];
[subject sendNext:subSubject2];
[subSubject1 sendNext:@1];
[subSubject2 sendNext:@2];

RACReplaySubject

重復提供信號類,繼承自RACSubject,它可以先發送信號,再訂閱信號,原理就是將發送的信號內容保存了起來,當訂閱信號的時候再將之前保存的信號,由訂閱者一個一個的發送出來,而保存信號的容量由capacity來控制。

 RACReplaySubject *replaySubject = [RACReplaySubject replaySubjectWithCapacity:5];
 [replaySubject subscribeNext:^(id  _Nullable x) {
     //輸出1
     NSLog(@"%@",x);
 }];
 [replaySubject sendNext:@1];
 [replaySubject subscribeNext:^(id  _Nullable x) {
     //輸出1
     NSLog(@"%@",x);
 }];

RACMulticastConnection

這是一個組播連接類,是對信號的一個封裝處理,當一個信號被多次訂閱時,則會多次執行didSubscribe這個Block,造成副作用,而這個類就能避免多次執行didSubscribe,是一對多的單向數據流,一般用來處理信號被多次訂閱的情況。

__block int i = 0;
//創建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
    [subscriber sendNext:@(i)];
    i ++;
    return nil;
}];
//創建RACMulticastConnection對象
RACMulticastConnection *connect = [signal publish]
 [connect.signal subscribeNext:^(id  _Nullable x) {
    //輸出0
    NSLog(@"%@",x);
}];
[connect.signal subscribeNext:^(id  _Nullable x) {
    //輸出0,當再次訂閱時,不會再執行didSubscribe,所以并沒有i++
    NSLog(@"%@",x);
}];
//連接
[connect connect];
  • 方法解析及實現原理
  • publishmulticast:這是對RACMulticastConnection初始化方法的一個封裝,publish其實就是調用了multicast,并把創建好的RACSubject對象傳給它,而multicast也就是調用了RACMulticastConnection的初始化方法,將原始信號傳給source,把RACSubject對象傳給subject
  • 當我們訂閱connect.signal,其實就是訂閱subject,然后將subject的訂閱者保存起來,而調用[connect connect]的時候,會訂閱原始信號(source),而source的訂閱者就是subject,這時候subject就會執行[subject sendNext],之后就會遍歷subject所有的訂閱者,逐一發送信號,觸發外部subscribeNext回調。

RACCommand

這是一個命令類,可以把事件如何處理,事件中的數據如何傳遞,包裝到這個類中,他可以很方便的監控事件的執行過程,一般來說是在UI上的某些動作來觸發這些事件,比如點擊一個按鈕,RACCommand的實例能夠決定是否可以被執行,一般用于網絡請求,監控請求過程。

  • 公開的屬性及方法
@interface RACCommand: NSObject

//這是一個二階信號,表示信號中包含子信號,一般使用flatten或switchToLatest來降階
@property (nonatomic, strong, readonly) RACSignal<RACSignal<ValueType> *> *executionSignals;

//這個信號表示當前RACCommand是否正在執行,YES/NO
@property (nonatomic, strong, readonly) RACSignal<NSNumber *> *executing;

//這個信號表示RACCommand是否可用,如果初始化傳NO或者allowsConcurrentExecution=NO,那個這個信號返回NO,否則為YES
@property (nonatomic, strong, readonly) RACSignal<NSNumber *> *enabled;

//表示RACCommand執行過程中產生的錯誤信號,當對錯誤信號進行處理的時候應該subscribeNext去訂閱,而不是subscribeError。
@property (nonatomic, strong, readonly) RACSignal<NSError *> *errors;

//是否允許并發執行,默認為NO
@property (atomic, assign) BOOL allowsConcurrentExecution;

/**
 初始化
 @param signalBlock 返回信號的Block,在其內部進行保存,當進行execute的時候才會調用該Block
 @return self
 */
- (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

/**
 初始化
 @param enabledSignal 是否可用
 @param signalBlock 返回信號的Block,在其內部進行保存,當進行execute的時候才會調用該Block
 @return self
 */
- (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

/**
 執行
 @param input 輸出內容
 @return 組播連接對象的signal
 */
- (RACSignal<ValueType> *)execute:(nullable InputType)input;

@end
  • 使用步驟:
  1. 創建命令,初始化RACCommand對象,內部做的事情:
  • 將傳入的signalBlock進行保存
  • 初始化自己的4個信號,executionSignalsexecutingenablederrors
  1. signalBlock中創建RACSignal,用來做數據傳遞,如果不需要可以創建空信號[RACSignal empty]
  2. 執行命令execute,內部做的事情:
  • 調用之前保存的signalBlock,并將execute參數帶入進去,拿到signalBlock返回的信號。
  • 再將該信號內容切換到主線程,然后multicastRACMulticastConnection對象,避免多次訂閱導致重復創建信號。
  • 將connection.signal mapexecutionSignals,當原始信號發送數據的時候,通過switchToLatestflatten來降階取值。
  //1.創建命令對象
  RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
      //輸出1,由execute傳入
      NSLog(@"%@",input);
      //2.創建信號
      return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
          [subscriber sendNext:@(2)];
          // 注意:數據傳遞完,最好調用sendCompleted,這時命令才執行完畢。
          [subscriber sendCompleted];
          return nil;
      }];
  }];

  //獲取信號傳輸的數據
  [command.executionSignals.switchToLatest subscribeNext:^(id x) {
      //輸出2
      NSLog(@"%@",x);
  }];
  //這里用flatten跟switchToLatest也是一樣的
  [[command.executionSignals flatten] subscribeNext:^(id  _Nullable x) {
      //輸出2
      NSLog(@"%@",x);
  }];

  //監聽命令是否執行完畢,初始化時會調用一次,用skip直接跳過。
  [[command.executing skip:1] subscribeNext:^(id x) {
      if ([x boolValue] == YES) {
          // 正在執行
          NSLog(@"正在執行");
      }else{
          // 執行完成
          NSLog(@"執行完成");
      }
  }];

  //3.執行命令
  RACSignal *connectSignal = [command execute:@1] ;
  [connectSignal subscribeNext:^(id  _Nullable x) {
      //輸出2,connectSignal是connect.signal
      NSLog(@"%@",x);
  }];

RACChannel

這是一個通道類,可以理解為一個雙向的連接,連接的兩端都配有RACChannelTerminal(通道終端,繼承自RACSignal,且又實現了RACSubscriber協議,所以它可以充當信號,又能發送信號),分別是leadingTerminalfollowingTerminal,只要其中任何一端輸出信號,另一端都會有相同的信號輸出。我們平時很少直接使用RACChannel,而是使用RACChannelTo

  • RACChannelTo:使用這個宏要傳入相關對象以及它的屬性,比如RACChannelTo(view,backgroundColor),實際上創建了一個RACKVOChannel對象,在內部將其一端的leadingTerminal與view的backgroundColor屬性進行綁定,并將其另一端followingTerminal暴露出來,也就是RACChannelTo的返回值,我們可以對followingTerminal進行訂閱,拿到view. backgroundColor,同樣followingTerminal發送信號也會同步到view.backgroundColor。

  • 用它來實現雙向綁定,RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);將button跟view的背景顏色進行綁定,兩邊相互影響,進行同步。

    RACChannelTerminal *followT = RACChannelTo(view,backgroundColor);
    [followT subscribeNext:^(id  _Nullable x) {
        //每點擊一次就輸出一次隨機顏色
        NSLog(@"%@",x);
    }];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
    [tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        //改變view.backgroundColor
        [followT sendNext:RandomColor];
    }];

    //將_textField.backgroundColor跟view.backgroundColor綁定
    RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);

常用宏

  • RAC(TARGET, ...):給某個對象的某個屬性進行綁定。
  //當textfield開始編輯時,關閉button響應
 RAC(_button,enabled) = [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] mapReplace:@NO];
  • RACObserve(TARGET, KEYPATH):KVO,監聽某個對象的屬性,返回的是信號。
[RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
    //x==新背景顏色
    NSLog(@"%@",x);
}];
  • RACChannelTo:用于雙向綁定的一個通道終端。
//將_textField.backgroundColor跟view.backgroundColor綁定
  RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);
  • RACTuplePack:將數據包裝成RACTuple(元組)。
RACTuple *tuple = RACTuplePack(@1,@2,@"3");
  • RACTupleUnpack(...):把元組解包成對應的數據
 //傳入需要解析生成的變量名,從第一個開始解析
 RACTupleUnpack(NSNumber *num1,NSNumber *num2) = tuple;
 //輸出1,2
 NSLog(@"%@,%@",num1,num2);
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容