Reactivecocoa(RAC)使用學(xué)習(xí)(全)

RAC使用容易忽略掉一些細(xì)節(jié),從而出現(xiàn)內(nèi)存泄漏,注意??

ReactiveCocoa結(jié)合了幾種編程風(fēng)格:

函數(shù)式編程(Functional Programming)
響應(yīng)式編程(Reactive Programming)

ReactiveCocoa被描述為函數(shù)響應(yīng)式編程(FRP)框架

一、常見的類學(xué)習(xí):

1、RACSignal

    /*RACSignal:有數(shù)據(jù)產(chǎn)生的時(shí)候就使用
     使用步驟:1、創(chuàng)建信號(hào);2、訂閱信號(hào);3、發(fā)送信號(hào);
     */
    
    //1、創(chuàng)建信號(hào)(冷信號(hào))
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //有返回值的block,_Nullable可為空
        
        /*
         這個(gè)block叫didSubscribe
         調(diào)用:只要一個(gè)信號(hào)被訂閱就會(huì)調(diào)用
         作用:發(fā)送數(shù)據(jù)
         */
        
        NSLog(@"信號(hào)被訂閱");
        
        //3、發(fā)送數(shù)據(jù)
        [subscriber sendNext:@1];
        
        
        return nil;
    }];
    
    //2、訂閱信號(hào)(熱信號(hào))
    [signal subscribeNext:^(id  _Nullable x) {
        
        /*
         nextBlock
         調(diào)用:只要訂閱者發(fā)送數(shù)據(jù)就會(huì)調(diào)用
         作用:接收數(shù)據(jù),處理數(shù)據(jù),展示到UI上
         */
        
        //x:信號(hào)發(fā)送的內(nèi)容
        
        NSLog(@"-----%@",x);
        
    }];
    
    /*
     只要訂閱者調(diào)用sendNext,就會(huì)執(zhí)行nextBlock
     只要訂閱RACDynamicSignal類型的信號(hào),就會(huì)執(zhí)行didSubscribe
     前提條件:一定要是RACDynamicSignal,不同類型的信號(hào),處理訂閱的事情不一樣
     */

2、RACSubscriber

表示訂閱者的意思,用于發(fā)送信號(hào),這是一個(gè)協(xié)議,不是一個(gè)類,只要遵守這個(gè)協(xié)議,并且實(shí)現(xiàn)方法才能成為訂閱者。通過create創(chuàng)建的信號(hào),都有一個(gè)訂閱者,幫助他發(fā)送數(shù)據(jù)。

3、RACDisposable

    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        //用屬性保存下來,防止subscriber自動(dòng)銷毀
        _subscriber = subscriber;
        
        [subscriber sendNext:@123];
        
        return [RACDisposable disposableWithBlock:^{
            /*
             只要訂閱取消就會(huì)來到這里
             作用:清空資源
             */
            NSLog(@"信號(hào)被取消訂閱了");
        }];
    }];
    
    RACDisposable *disposable = [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"----------%@",x);
    }];
    
    /*
     默認(rèn)一個(gè)信號(hào)發(fā)送完畢就會(huì)取消信號(hào)訂閱
     但是只要訂閱者在,就不會(huì)自動(dòng)取消信號(hào)訂閱
     */
    
    //手動(dòng)取消訂閱信號(hào)
    [disposable dispose];

4、RACSubject (代替代理)

    /*
     RACSubject:信號(hào)提供者,自己可以充當(dāng)信號(hào),又能發(fā)送信號(hào)
     
     想要某個(gè)類擁有多個(gè)類的功能,就可以繼承一個(gè)類,再遵守協(xié)議,這叫做面向協(xié)議的思想
     */
    
    //1、創(chuàng)建信號(hào)
    RACSubject *subject = [RACSubject subject];
    
    //2、訂閱信號(hào)
    //RACSubject:僅僅保存訂閱者
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"1、接收到數(shù)據(jù):%@",x);
    }];
    
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"2、接收到數(shù)據(jù):%@",x);
    }];
    
    //3、發(fā)送數(shù)據(jù)
    [subject sendNext:@123];
    //底層實(shí)現(xiàn):遍歷訂閱者,調(diào)用nextBlock

5、RACReplaySubject (可以先發(fā)送信號(hào)再訂閱)

    //1、創(chuàng)建信號(hào)
    RACReplaySubject *replaySubject = [RACReplaySubject subject];
    
    //3、發(fā)送信號(hào)
    [replaySubject sendNext:@1111];
    
    //2、訂閱信號(hào)
    [replaySubject subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    //遍歷所有的值,拿到當(dāng)前訂閱者去發(fā)送數(shù)據(jù)
    
    /*
     RACReplaySubject發(fā)送數(shù)據(jù):
     1、保存值
     2、遍歷所有的訂閱者,發(fā)送數(shù)據(jù)
     
     RACReplaySubject可以先發(fā)送信號(hào)再訂閱
     */
     
     

6、RACMulticastConnection

用法:當(dāng)一個(gè)信號(hào),被多次訂閱時(shí),為了保證創(chuàng)建信號(hào)時(shí),避免多次調(diào)用創(chuàng)建信號(hào)中的block,也就是請(qǐng)求數(shù)據(jù)的block,造成副作用,可以使用這個(gè)類處理。
使用注意:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創(chuàng)建.
eg:信號(hào)被多次訂閱的時(shí)候,會(huì)重復(fù)請(qǐng)求數(shù)據(jù)

代碼:


    RACSignal *s0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"---請(qǐng)求數(shù)據(jù)");
        [subscriber sendNext:@"得到的數(shù)據(jù)"];
        
        return nil;
    }];
    
    [s0 subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [s0 subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

輸出:

2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---請(qǐng)求數(shù)據(jù)
2017-07-28 10:17:37.837 RAC_learning[1180:38354] 得到的數(shù)據(jù)
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---請(qǐng)求數(shù)據(jù)
2017-07-28 10:17:37.838 RAC_learning[1180:38354] 得到的數(shù)據(jù)

這樣導(dǎo)致了多次請(qǐng)求數(shù)據(jù),所以用RACMulticastConnection可以實(shí)現(xiàn)不論多少次訂閱,只請(qǐng)求一次數(shù)據(jù)

eg:用RACMulticastConnection
    //1、創(chuàng)建信號(hào)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"---請(qǐng)求數(shù)據(jù)");
        [subscriber sendNext:@"得到的數(shù)據(jù)"];
        
        return nil;
    }];
    
    //2、把信號(hào)轉(zhuǎn)換成連接類
    RACMulticastConnection *connection = signal.publish;
    //或者
    //RACMulticastConnection *connection = [signal multicast:[RACReplaySubject subject]];
    
    
    //3、訂閱信號(hào)
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"第一次獲取:%@",x);
    }];
    
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"第二次獲?。?@",x);
    }];
    
    //4、連接
    [connection connect];

輸出

2017-07-28 10:22:09.098 RAC_learning[1243:41311] ---請(qǐng)求數(shù)據(jù)
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第一次獲?。旱玫降臄?shù)據(jù)
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第二次獲?。旱玫降臄?shù)據(jù)

7、RACCommand

RAC中用于處理事件的類,可以把事件如何處理,事件中的數(shù)據(jù)如何傳遞,包裝到這個(gè)類中,他可以很方便的監(jiān)控事件的執(zhí)行過程。

使用場(chǎng)景:監(jiān)聽按鈕點(diǎn)擊,網(wǎng)絡(luò)請(qǐng)求

(1)==RACCommand==


    //1、創(chuàng)建命令
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        
        //得到執(zhí)行命令傳入?yún)?shù)
        NSLog(@"得到執(zhí)行命令傳入?yún)?shù)input = %@",input);
        
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            
            [subscriber sendNext:@"請(qǐng)求到的數(shù)據(jù)"];
            
            return nil;
        }];
        
    }];
    
    /*
      如何拿到執(zhí)行命令中產(chǎn)生的數(shù)據(jù)
      訂閱命令內(nèi)部的信號(hào)
      1.方式一:直接訂閱執(zhí)行命令返回的信號(hào)(execute方法返回RACSignal)
      2.方式二:executionSignals:獲取信號(hào)源
     */
    
    //2、執(zhí)行命令
    
    //方式一:直接訂閱執(zhí)行命令返回的信號(hào)(execute方法返回RACSignal)  必須在執(zhí)行命令之后執(zhí)行
    
    /*
    RACSignal *signal = [command execute:@1];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
     */
    
    //方式二:executionSignals:獲取信號(hào)源  必須在執(zhí)行命令之前執(zhí)行
    
    /*
    [command.executionSignals subscribeNext:^(RACSignal *x) {
       //這里獲取到的是RACSignal
        [x subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
    }];
     */
    
    //switchToLatest:得到信號(hào)源中最新的信號(hào)
    [command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [command execute:@1];

(2)==switchToLatest==:得到信號(hào)源中最新的信號(hào)

    // 創(chuàng)建信號(hào)中信號(hào)
    RACSubject *signalOfSignals = [RACSubject subject];
    RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];
    
    //只會(huì)得到最新的發(fā)送的信號(hào)signalB
    [signalOfSignals.switchToLatest subscribeNext:^(id x) {
        
        NSLog(@"%@",x);
    }];
    
    // 發(fā)送信號(hào)
    [signalOfSignals sendNext:signalA];
    
    [signalOfSignals sendNext:signalB];

    
    [signalA sendNext:@1];
    [signalB sendNext:@"BB"];
    [signalA sendNext:@"11"];

(3)==executing==:監(jiān)聽事件有沒有完成

    // 1.創(chuàng)建命令
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        
        NSLog(@"%@",input);
        
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            // 發(fā)送數(shù)據(jù)
            [subscriber sendNext:@"執(zhí)行命令產(chǎn)生的數(shù)據(jù)"];
            
            // 主動(dòng)發(fā)送完成,這樣才會(huì)監(jiān)聽到發(fā)送完成的時(shí)候
            [subscriber sendCompleted];
            
            return nil;
        }];
    }];
    
    // 監(jiān)聽事件有沒有完成
    [command.executing subscribeNext:^(id x) {
        if ([x boolValue] == YES) {
            // 當(dāng)前正在執(zhí)行
            NSLog(@"當(dāng)前正在執(zhí)行");
        }else{
            // 執(zhí)行完成/沒有執(zhí)行
            NSLog(@"執(zhí)行完成/沒有執(zhí)行");
        }
    }];
    
    
    // 2.執(zhí)行命令
    [command execute:@1];

二、集合類學(xué)習(xí)

1、RACTuple

(1)當(dāng)作數(shù)組用

RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"456",@789]];
    
    NSString *string = tuple[0];
    
    NSLog(@"%@",string);

2、RACSequence

(1)當(dāng)作數(shù)組用

NSArray *array = @[@"123",@"456",@789];
    //數(shù)組轉(zhuǎn)集合
    RACSequence *sequence = array.rac_sequence;
    //集合轉(zhuǎn)信號(hào)
    RACSignal *signal = sequence.signal;
    //遍歷
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    //簡單寫法------------
    [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

(2)當(dāng)集合用

    NSDictionary *dict = @{@"account":@"aaa",@"name":@"xmg",@"age":@18};
    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
//        NSString *key = x[0];
//        NSString *value = x[1];
//        NSLog(@"%@  %@",key,value);
        
        // RACTupleUnpack:用來解析元組
        // 宏里面的參數(shù),傳需要解析出來的變量名
        // = 右邊,放需要解析的元組
        RACTupleUnpack(NSString *key, NSString *value) = x;
        
        NSLog(@"%@  %@", key, value);
    }];
    
    
    NSArray *dictArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil]];
    
    NSMutableArray *array = [NSMutableArray array];
    [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *dict) {
        Flag *flag = [Flag flagWithDict:dict];
        [array addObject:flag];
    }];
    
    //更高級(jí)點(diǎn)的用法
    NSArray *flagArr = [[dictArr.rac_sequence map:^id _Nullable(NSDictionary *dict) {
        return [Flag flagWithDict:dict];
    }] array];

三、開發(fā)中常見用法 (轉(zhuǎn)換成信號(hào)然后訂閱)

1、代替代理:

(1)RACSubject :可以傳值
(2)rac_signalForSelector :無法傳值
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
    NSLog(@"控制器知道按鈕被點(diǎn)擊");
}];

2、代替KVO :

rac_valuesForKeyPath:用于監(jiān)聽某個(gè)對(duì)象的屬性改變。
[[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
    // x:修改的值
    NSLog(@"%@",x);
}];

3、監(jiān)聽事件:

rac_signalForControlEvents:用于監(jiān)聽某個(gè)事件。
    [[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"按鈕點(diǎn)擊了");
    }];

4、代替通知:

rac_addObserverForName:用于監(jiān)聽某個(gè)通知。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
        
        NSLog(@"%@",x);
    }];

5、監(jiān)聽文本框文字改變:

rac_textSignal:只要文本框發(fā)出改變就會(huì)發(fā)出這個(gè)信號(hào)。
[_textField.rac_textSignal subscribeNext:^(id x) {
       
        NSLog(@"%@",x);
    }];

6、處理當(dāng)界面有多次請(qǐng)求時(shí),需要都獲取到數(shù)據(jù)時(shí),才能展示界面

rac_liftSelector:withSignalsFromArray:
Signals:當(dāng)傳入的Signals(信號(hào)數(shù)組),每一個(gè)signal都至少sendNext過一次,就會(huì)去觸發(fā)第一個(gè)selector參數(shù)的方法。
使用注意:幾個(gè)信號(hào),參數(shù)一的方法就幾個(gè)參數(shù),每個(gè)參數(shù)對(duì)應(yīng)信號(hào)發(fā)出的數(shù)據(jù)。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    RACSignal *signal0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //這里進(jìn)行網(wǎng)絡(luò)請(qǐng)求
        [subscriber sendNext:@"0000000"];
        return nil;
    }];
    
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //這里進(jìn)行網(wǎng)絡(luò)請(qǐng)求
        [subscriber sendNext:@"1111111"];
        return nil;
    }];
    
    /*
     selector方法參數(shù)個(gè)數(shù)必須與信號(hào)數(shù)組個(gè)數(shù)一致,表示獲得到的數(shù)據(jù)
     rac_liftSelector:必須信號(hào)數(shù)組中的信號(hào)都發(fā)送數(shù)據(jù)才會(huì)進(jìn)入selector方法中
     */
    [self rac_liftSelector:@selector(updateUIWithOne:two:) withSignalsFromArray:@[signal0, signal1]];
    
}

- (void)updateUIWithOne:(NSString *)one two:(NSString *)two{
    
    NSLog(@"one = %@;\ntwo = %@",one,two);
    
}

四、常見的宏

1、RAC(<#TARGET, ...#>):用于給某個(gè)對(duì)象的某個(gè)屬性綁定

// 監(jiān)聽文本框內(nèi)容

[_textField.rac_textSignal subscribeNext:^(id x) {
    _label.text = x;
}];

//使用RAC宏:    
// 用來給某個(gè)對(duì)象的某個(gè)屬性綁定信號(hào),只要產(chǎn)生信號(hào)內(nèi)容,就會(huì)把內(nèi)容給屬性賦值
RAC(_label,text) = _textField.rac_textSignal;

2、RACObserve(self, name):監(jiān)聽某個(gè)對(duì)象的某個(gè)屬性,返回的是信號(hào)

[RACObserve(self.view, frame) subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];

3、@weakify(Obj)和@strongify(Obj),一般兩個(gè)都是配套使用,解決循環(huán)引用問題.

//在block外使用@weakify(self),在block內(nèi)使用@strongify(self),可以防止block內(nèi)使用self出現(xiàn)循環(huán)引用

4、RACTuplePack:把數(shù)據(jù)包裝成RACTuple(元組類)

// 包裝元組
RACTuple *tuple = RACTuplePack(@1,@2);
    
NSLog(@"%@",tuple[0]);

5、RACTupleUnpack:把RACTuple(元組類)解包成對(duì)應(yīng)的數(shù)據(jù)

NSDictionary *dict = @{@"account":@"aaa",@"name":@"xmg",@"age":@18};
[dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

    // RACTupleUnpack:用來解析元組
    // 宏里面的參數(shù),傳需要解析出來的變量名
    // = 右邊,放需要解析的元組
    RACTupleUnpack(NSString *key, NSString *value) = x;
    
    NSLog(@"%@  %@", key, value);
}];

五、常見操作方法

ReactiveCocoa操作思想

運(yùn)用的是==Hook(鉤子)思想==,Hook是一種用于改變API(應(yīng)用程序編程接口:方法)執(zhí)行結(jié)果的技術(shù).
Hook用處:截獲API調(diào)用的技術(shù)。
Hook原理:在每次調(diào)用一個(gè)API返回結(jié)果之前,先執(zhí)行你自己的方法,改變結(jié)果的輸出。

RAC開發(fā)方式:RAC中核心開發(fā)方式,也是綁定,之前的開發(fā)方式是賦值,而用RAC開發(fā),應(yīng)該把重心放在綁定,也就是可以在創(chuàng)建一個(gè)對(duì)象的時(shí)候,就綁定好以后想要做的事情,而不是等賦值之后在去做事情。
列如:把數(shù)據(jù)展示到控件上,之前都是重寫控件的setModel方法,用RAC就可以在一開始創(chuàng)建控件的時(shí)候,就綁定好數(shù)據(jù)。

1、核心方法bind

一般不會(huì)使用bind方法,因?yàn)楸容^底層
給RAC中的信號(hào)進(jìn)行綁定,只要信號(hào)一發(fā)送數(shù)據(jù),就能監(jiān)聽到,從而把發(fā)送數(shù)據(jù)改成自己想要的數(shù)據(jù)

    RACSubject *subject = [RACSubject subject];
    
    RACSignal *bindSignal = [subject bind:^RACSignalBindBlock _Nonnull{
        
        return ^RACSignal *(id _Nullable value, BOOL *stop){
            
            value = [NSString stringWithFormat:@"changed:%@",value];
            
            /*
             在這里修改獲取到的數(shù)據(jù)
             */
            
            return [RACReturnSignal return:value];
        };
        
    }];
    
    [bindSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@"數(shù)據(jù)"];

監(jiān)聽文本框的內(nèi)容,并綁定

[[self.textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{
        return ^RACSignal *(id _Nullable value, BOOL *stop){
            value = [NSString stringWithFormat:@"輸出:%@",value];
            return [RACReturnSignal return:value];
        };
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

2、ReactiveCocoa操作方法之映射(flattenMap,Map)

(1)falttenMap


    //1、創(chuàng)建信號(hào)
    RACSubject *subject = [RACSubject subject];
    
    //2、綁定信號(hào)
    RACSignal *bindSignal = [subject flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
        
        //這里的block只要原信號(hào)發(fā)送數(shù)據(jù)就會(huì)調(diào)用
        value = [NSString stringWithFormat:@"lcy:%@",value];
        
        return [RACReturnSignal return:value];
        
    }];
    
    //3、訂閱信號(hào)
    [bindSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    //4、發(fā)送數(shù)據(jù)
    [subject sendNext:@"hello"];

(2)map


    RACSubject *subject = [RACSubject subject];
    
    RACSignal *bindSignal = [subject map:^id _Nullable(id  _Nullable value) {
        //這里返回的值就是需要映射的值
        return [NSString stringWithFormat:@"dashabi:%@",value];
    }];
    
    [bindSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@"123123"];
    [subject sendNext:@"123123123"];

3、ReactiveCocoa操作方法之組合

(1)concat

按一定順序拼接信號(hào),當(dāng)多個(gè)信號(hào)發(fā)出的時(shí)候,有順序的接收信號(hào)。

==注意==:組合中第一個(gè)信號(hào)一定要調(diào)用sendComplete

    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送A的數(shù)據(jù)");
        
        [subscriber sendNext:@"hello A"];
        
        [subscriber sendCompleted];
        
        return nil;
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送B的數(shù)據(jù)");

        [subscriber sendNext:@"hello B"];

        return nil;
    }];
    
    RACSignal *concatSignal = [signalA concat:signalB];
    
    [concatSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

輸出:

2017-07-28 16:33:57.588 RAC_learning[3169:192908] 發(fā)送A的數(shù)據(jù)
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello A
2017-07-28 16:33:57.589 RAC_learning[3169:192908] 發(fā)送B的數(shù)據(jù)
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello B

(2)then

用于連接兩個(gè)信號(hào),當(dāng)?shù)谝粋€(gè)信號(hào)完成,才會(huì)連接then返回的信號(hào),then會(huì)完全忽略第一個(gè)信號(hào)的數(shù)據(jù)

==注意==:組合中第一個(gè)信號(hào)一定要調(diào)用sendComplete

RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送A的數(shù)據(jù)");
        
        [subscriber sendNext:@"hello A"];
        
        [subscriber sendCompleted];
        
        return nil;
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送B的數(shù)據(jù)");

        [subscriber sendNext:@"hello B"];

        return nil;
    }];
    
    RACSignal *signal = [signalA then:^RACSignal * _Nonnull{
        return signalB;
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

輸出:

2017-07-28 16:38:18.436 RAC_learning[3280:196164] 發(fā)送A的數(shù)據(jù)
2017-07-28 16:38:18.440 RAC_learning[3280:196164] 發(fā)送B的數(shù)據(jù)
2017-07-28 16:38:18.440 RAC_learning[3280:196164] hello B

(3)merge

把多個(gè)信號(hào)合并為一個(gè)信號(hào),任何一個(gè)信號(hào)有新值的時(shí)候就會(huì)調(diào)用

不需要調(diào)用sendComplete

    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送A的數(shù)據(jù)");
        
        [subscriber sendNext:@"hello A"];
        
        return nil;
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送B的數(shù)據(jù)");

        [subscriber sendNext:@"hello B"];

        return nil;
    }];
    
    RACSignal *signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        return nil;
    }];
    
    RACSignal *signal = [[signalA merge:signalB] merge:signalC];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

輸出:

2017-07-28 16:46:06.471 RAC_learning[3563:202620] 發(fā)送A的數(shù)據(jù)
2017-07-28 16:46:06.471 RAC_learning[3563:202620] hello A
2017-07-28 16:46:06.471 RAC_learning[3563:202620] 發(fā)送B的數(shù)據(jù)
2017-07-28 16:46:06.472 RAC_learning[3563:202620] hello B

(4)zipWith

把兩個(gè)信號(hào)壓縮成一個(gè)信號(hào),只有當(dāng)兩個(gè)信號(hào)同時(shí)發(fā)出信號(hào)內(nèi)容時(shí),并且把兩個(gè)信號(hào)的內(nèi)容合并成一個(gè)==元組==(RACTuple),才會(huì)觸發(fā)壓縮流的next事件

RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送A的數(shù)據(jù)");
        
        [subscriber sendNext:@"hello A"];
        
        return nil;
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"發(fā)送B的數(shù)據(jù)");

        [subscriber sendNext:@"hello B"];

        return nil;
    }];
    
    RACSignal *signal = [signalA zipWith:signalB];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

輸出:

2017-07-28 16:52:44.200 RAC_learning[3630:205690] 發(fā)送A的數(shù)據(jù)
2017-07-28 16:52:44.201 RAC_learning[3630:205690] 發(fā)送B的數(shù)據(jù)
2017-07-28 16:52:44.204 RAC_learning[3630:205690] <RACTwoTuple: 0x6000000173b0> (
    "hello A",
    "hello B"
)

(5)combineLatest

將多個(gè)信號(hào)合并起來,并且拿到各個(gè)信號(hào)的最新的值,必須每個(gè)合并的signal至少都有過一次sendNext,才會(huì)觸發(fā)合并的信號(hào)

(6)reduce

用于信號(hào)發(fā)出的內(nèi)容是元組,把信號(hào)發(fā)出元組的值聚合成一個(gè)值

RACSignal *signal = [RACSignal combineLatest:@[self.nameTF.rac_textSignal, self.passwordTF.rac_textSignal] reduce:^id _Nullable(NSString *name, NSString *password){
        
        NSLog(@"%@  ooooo  %@",name, password);
        
        return @(name.length && password.length);
    }];

//    [signal subscribeNext:^(id  _Nullable x) {
//        NSLog(@"得到的數(shù)據(jù):%@",x);
//    }];
    
    //使登錄按鈕在用戶名和密碼框都有數(shù)據(jù)的時(shí)候才會(huì)調(diào)用
    RAC(self.loginButton, enabled) = signal;

4、ReactiveCocoa操作方法之過濾

(1)filter

過濾信號(hào),使用它可以獲取滿足條件的信號(hào)

RACSignal *signal = [self.nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
        
        //表示當(dāng)文本框輸入的長度超過六位的時(shí)候

        return value.length > 6;
        
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        //只有滿足條件的時(shí)候才會(huì)進(jìn)入這個(gè)block

        NSLog(@"%@",x);
    }];

(2)ignore

忽略完某些值的信號(hào).

[[self.nameTF.rac_textSignal ignore:@"000"] subscribeNext:^(NSString * _Nullable x) {
       //忽略了字符串是000的值
       NSLog(@"%@",x);
    }];

(3)distinctUntilChanged

當(dāng)上一次的值和當(dāng)前的值有明顯的變化就會(huì)發(fā)出信號(hào),否則會(huì)被忽略掉

[[self.nameTF.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);
    }];

(4)take

從開始一共取N次的信號(hào)

[[self.nameTF.rac_textSignal take:3] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);
    }];
// 1、創(chuàng)建信號(hào)
RACSubject *signal = [RACSubject subject];

// 2、處理信號(hào),訂閱信號(hào)
[[signal take:1] subscribeNext:^(id x) {

  NSLog(@"%@",x);
}];

// 3.發(fā)送信號(hào)
[signal sendNext:@1];

[signal sendNext:@2];

(5)takeLast

取最后N次的信號(hào)
==前提條件==:訂閱者必須調(diào)用完成,因?yàn)橹挥型瓿桑椭揽偣灿卸嗌傩盘?hào)
==注意==:一定要調(diào)用sendComplete,不然訂閱者不知道有多少

RACSubject *subject = [RACSubject subject];
    
    [[subject takeLast:3] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@1];
    [subject sendNext:@2];
    [subject sendNext:@3];
    [subject sendNext:@4];
    [subject sendNext:@5];

    
    [subject sendCompleted];

(6)takeUntil

獲取信號(hào)直到執(zhí)行完這個(gè)信號(hào)

RACSubject *subject = [RACSubject subject];
    
    RACSubject *signal = [RACSubject subject];
    
    [[subject takeUntil:signal] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@1];
    [subject sendNext:@2];
    
    /*
    sendNext或者sendComplete都可以截止
    sendError不可以
    */
    [signal sendCompleted];
    
    
    [subject sendNext:@3];
    [subject sendNext:@4];
    [subject sendNext:@5];
    
    
    [subject sendCompleted];
// 監(jiān)聽文本框的改變,直到當(dāng)前對(duì)象被銷毀
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];

(7)skip:(NSUInteger)

跳過幾個(gè)信號(hào),不接受

[[self.nameTF.rac_textSignal skip:3] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);
    }];

5、ReactiveCocoa操作方法之秩序

doNext: 執(zhí)行Next之前,會(huì)先執(zhí)行這個(gè)Block

doCompleted: 執(zhí)行sendCompleted之前,會(huì)先執(zhí)行這個(gè)Block

[[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"hahaha"];
        [subscriber sendCompleted];
        return nil;
    }] doNext:^(id  _Nullable x) {
        NSLog(@"doNext");
    }] doCompleted:^{
        NSLog(@"doComplete");
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

輸出:

2017-07-28 18:12:56.704 RAC_learning[5256:261194] doNext
2017-07-28 18:12:56.705 RAC_learning[5256:261194] hahaha
2017-07-28 18:12:56.705 RAC_learning[5256:261194] doComplete

6、ReactiveCocoa操作方法之線程

deliverOn: 內(nèi)容傳遞切換到制定線程中,副作用在原來線程中,把在創(chuàng)建信號(hào)時(shí)block中的代碼稱之為副作用。

subscribeOn: 內(nèi)容傳遞和副作用都會(huì)切換到制定線程中。

7、ReactiveCocoa操作方法之時(shí)間

(1)timeout

超時(shí),可以讓一個(gè)信號(hào)在一定的時(shí)間后,自動(dòng)報(bào)錯(cuò)

RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        return nil;
    }] timeout:1 onScheduler:[RACScheduler currentScheduler]];
    
    [signal subscribeNext:^(id x) {
        
        NSLog(@"%@",x);
    } error:^(NSError *error) {
        // 1秒后會(huì)自動(dòng)調(diào)用
        NSLog(@"%@",error);
    }];

(2)interval

定時(shí),每隔一段時(shí)間發(fā)出信號(hào)

RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"123123123"];
        return nil;
    }];
    
    [[RACSignal interval:2.0 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"%@",x);
        [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
    }];

(3)delay

延遲發(fā)送next

[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"123123123"];
        return nil;
    }] delay:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

8、ReactiveCocoa操作方法之重復(fù)

(1)retry重試

只要失敗,就會(huì)重新執(zhí)行創(chuàng)建信號(hào)中的block,直到成功.

__block int i = 0;
    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

            if (i == 10) {
                [subscriber sendNext:@1];
            }else{
                NSLog(@"接收到錯(cuò)誤");
                [subscriber sendError:nil];
            }
            i++;

        return nil;

    }] retry] subscribeNext:^(id x) {

        NSLog(@"%@",x);

    } error:^(NSError *error) {


    }];

(2)replay重放

當(dāng)一個(gè)信號(hào)被多次訂閱,反復(fù)播放內(nèi)容

RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    //只會(huì)進(jìn)入這個(gè)block一次,不會(huì)反復(fù)進(jìn)入

        [subscriber sendNext:@1];
        [subscriber sendNext:@2];

        return nil;
    }] replay];

    [signal subscribeNext:^(id x) {

        NSLog(@"第一個(gè)訂閱者%@",x);

    }];

    [signal subscribeNext:^(id x) {

        NSLog(@"第二個(gè)訂閱者%@",x);

    }];

(3)throttle節(jié)流

當(dāng)某個(gè)信號(hào)發(fā)送比較頻繁時(shí),可以使用節(jié)流,在某一段時(shí)間不發(fā)送信號(hào)內(nèi)容,過了一段時(shí)間獲取信號(hào)的最新內(nèi)容發(fā)出。
R

ACSubject *signal = [RACSubject subject];

    _signal = signal;

    // 節(jié)流,在一定時(shí)間(1秒)內(nèi),不接收任何信號(hào)內(nèi)容,過了這個(gè)時(shí)間(1秒)獲取最后發(fā)送的信號(hào)內(nèi)容發(fā)出。
    [[signal throttle:1] subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容