Reactivecocoa(RAC)使用學習(全)

RAC使用容易忽略掉一些細節(jié)送粱,從而出現(xiàn)內存泄漏橙依,注意??

ReactiveCocoa結合了幾種編程風格:

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

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

一、常見的類學習:

1训枢、RACSignal

    /*RACSignal:有數(shù)據產生的時候就使用
     使用步驟:1踩寇、創(chuàng)建信號;2藏古、訂閱信號;3忍燥、發(fā)送信號拧晕;
     */
    
    //1、創(chuàng)建信號(冷信號)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //有返回值的block灾前,_Nullable可為空
        
        /*
         這個block叫didSubscribe
         調用:只要一個信號被訂閱就會調用
         作用:發(fā)送數(shù)據
         */
        
        NSLog(@"信號被訂閱");
        
        //3防症、發(fā)送數(shù)據
        [subscriber sendNext:@1];
        
        
        return nil;
    }];
    
    //2孟辑、訂閱信號(熱信號)
    [signal subscribeNext:^(id  _Nullable x) {
        
        /*
         nextBlock
         調用:只要訂閱者發(fā)送數(shù)據就會調用
         作用:接收數(shù)據哎甲,處理數(shù)據,展示到UI上
         */
        
        //x:信號發(fā)送的內容
        
        NSLog(@"-----%@",x);
        
    }];
    
    /*
     只要訂閱者調用sendNext饲嗽,就會執(zhí)行nextBlock
     只要訂閱RACDynamicSignal類型的信號炭玫,就會執(zhí)行didSubscribe
     前提條件:一定要是RACDynamicSignal,不同類型的信號浦楣,處理訂閱的事情不一樣
     */

2馍资、RACSubscriber

表示訂閱者的意思疗杉,用于發(fā)送信號,這是一個協(xié)議衔憨,不是一個類,只要遵守這個協(xié)議袄膏,并且實現(xiàn)方法才能成為訂閱者践图。通過create創(chuàng)建的信號,都有一個訂閱者沉馆,幫助他發(fā)送數(shù)據码党。

3、RACDisposable

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

4、RACSubject (代替代理)

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

5座享、RACReplaySubject (可以先發(fā)送信號再訂閱)

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

6饺著、RACMulticastConnection

用法:當一個信號箫攀,被多次訂閱時,為了保證創(chuàng)建信號時幼衰,避免多次調用創(chuàng)建信號中的block靴跛,也就是請求數(shù)據的block,造成副作用渡嚣,可以使用這個類處理梢睛。
使用注意:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創(chuàng)建.
eg:信號被多次訂閱的時候,會重復請求數(shù)據

代碼:


    RACSignal *s0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"---請求數(shù)據");
        [subscriber sendNext:@"得到的數(shù)據"];
        
        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] ---請求數(shù)據
2017-07-28 10:17:37.837 RAC_learning[1180:38354] 得到的數(shù)據
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---請求數(shù)據
2017-07-28 10:17:37.838 RAC_learning[1180:38354] 得到的數(shù)據

這樣導致了多次請求數(shù)據识椰,所以用RACMulticastConnection可以實現(xiàn)不論多少次訂閱绝葡,只請求一次數(shù)據

eg:用RACMulticastConnection
    //1、創(chuàng)建信號
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"---請求數(shù)據");
        [subscriber sendNext:@"得到的數(shù)據"];
        
        return nil;
    }];
    
    //2腹鹉、把信號轉換成連接類
    RACMulticastConnection *connection = signal.publish;
    //或者
    //RACMulticastConnection *connection = [signal multicast:[RACReplaySubject subject]];
    
    
    //3藏畅、訂閱信號
    [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] ---請求數(shù)據
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第一次獲取:得到的數(shù)據
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第二次獲群讲t。旱玫降臄?shù)據

7诫硕、RACCommand

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

使用場景:監(jiān)聽按鈕點擊,網絡請求

(1)==RACCommand==


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

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

    // 創(chuàng)建信號中信號
    RACSubject *signalOfSignals = [RACSubject subject];
    RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];
    
    //只會得到最新的發(fā)送的信號signalB
    [signalOfSignals.switchToLatest subscribeNext:^(id x) {
        
        NSLog(@"%@",x);
    }];
    
    // 發(fā)送信號
    [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ù)據
            [subscriber sendNext:@"執(zhí)行命令產生的數(shù)據"];
            
            // 主動發(fā)送完成,這樣才會監(jiān)聽到發(fā)送完成的時候
            [subscriber sendCompleted];
            
            return nil;
        }];
    }];
    
    // 監(jiān)聽事件有沒有完成
    [command.executing subscribeNext:^(id x) {
        if ([x boolValue] == YES) {
            // 當前正在執(zhí)行
            NSLog(@"當前正在執(zhí)行");
        }else{
            // 執(zhí)行完成/沒有執(zhí)行
            NSLog(@"執(zhí)行完成/沒有執(zhí)行");
        }
    }];
    
    
    // 2.執(zhí)行命令
    [command execute:@1];

二休偶、集合類學習

1梁厉、RACTuple

(1)當作數(shù)組用

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

2、RACSequence

(1)當作數(shù)組用

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

(2)當集合用

    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];
    }];
    
    //更高級點的用法
    NSArray *flagArr = [[dictArr.rac_sequence map:^id _Nullable(NSDictionary *dict) {
        return [Flag flagWithDict:dict];
    }] array];

三踏兜、開發(fā)中常見用法 (轉換成信號然后訂閱)

1词顾、代替代理:

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

2、代替KVO :

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

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

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

4疹尾、代替通知:

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

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

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

6窍蓝、處理當界面有多次請求時,需要都獲取到數(shù)據時饮醇,才能展示界面

rac_liftSelector:withSignalsFromArray:
Signals:當傳入的Signals(信號數(shù)組)它抱,每一個signal都至少sendNext過一次秕豫,就會去觸發(fā)第一個selector參數(shù)的方法朴艰。
使用注意:幾個信號,參數(shù)一的方法就幾個參數(shù)混移,每個參數(shù)對應信號發(fā)出的數(shù)據祠墅。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    RACSignal *signal0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //這里進行網絡請求
        [subscriber sendNext:@"0000000"];
        return nil;
    }];
    
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //這里進行網絡請求
        [subscriber sendNext:@"1111111"];
        return nil;
    }];
    
    /*
     selector方法參數(shù)個數(shù)必須與信號數(shù)組個數(shù)一致,表示獲得到的數(shù)據
     rac_liftSelector:必須信號數(shù)組中的信號都發(fā)送數(shù)據才會進入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, ...#>):用于給某個對象的某個屬性綁定

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

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

//使用RAC宏:    
// 用來給某個對象的某個屬性綁定信號,只要產生信號內容,就會把內容給屬性賦值
RAC(_label,text) = _textField.rac_textSignal;

2、RACObserve(self, name):監(jiān)聽某個對象的某個屬性,返回的是信號

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

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

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

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

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

5腔长、RACTupleUnpack:把RACTuple(元組類)解包成對應的數(shù)據

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操作思想

運用的是==Hook(鉤子)思想==验残,Hook是一種用于改變API(應用程序編程接口:方法)執(zhí)行結果的技術.
Hook用處:截獲API調用的技術捞附。
Hook原理:在每次調用一個API返回結果之前,先執(zhí)行你自己的方法,改變結果的輸出鸟召。

RAC開發(fā)方式:RAC中核心開發(fā)方式胆绊,也是綁定,之前的開發(fā)方式是賦值欧募,而用RAC開發(fā)压状,應該把重心放在綁定,也就是可以在創(chuàng)建一個對象的時候跟继,就綁定好以后想要做的事情何缓,而不是等賦值之后在去做事情。
列如:把數(shù)據展示到控件上还栓,之前都是重寫控件的setModel方法碌廓,用RAC就可以在一開始創(chuàng)建控件的時候,就綁定好數(shù)據剩盒。

1谷婆、核心方法bind

一般不會使用bind方法,因為比較底層
給RAC中的信號進行綁定辽聊,只要信號一發(fā)送數(shù)據纪挎,就能監(jiān)聽到,從而把發(fā)送數(shù)據改成自己想要的數(shù)據

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

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

[[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)建信號
    RACSubject *subject = [RACSubject subject];
    
    //2玛臂、綁定信號
    RACSignal *bindSignal = [subject flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
        
        //這里的block只要原信號發(fā)送數(shù)據就會調用
        value = [NSString stringWithFormat:@"lcy:%@",value];
        
        return [RACReturnSignal return:value];
        
    }];
    
    //3烤蜕、訂閱信號
    [bindSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    //4、發(fā)送數(shù)據
    [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

按一定順序拼接信號讽营,當多個信號發(fā)出的時候,有順序的接收信號泡徙。

==注意==:組合中第一個信號一定要調用sendComplete

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

        [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ù)據
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ù)據
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello B

(2)then

用于連接兩個信號橱鹏,當?shù)谝粋€信號完成,才會連接then返回的信號堪藐,then會完全忽略第一個信號的數(shù)據

==注意==:組合中第一個信號一定要調用sendComplete

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

        [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ù)據
2017-07-28 16:38:18.440 RAC_learning[3280:196164] 發(fā)送B的數(shù)據
2017-07-28 16:38:18.440 RAC_learning[3280:196164] hello B

(3)merge

把多個信號合并為一個信號莉兰,任何一個信號有新值的時候就會調用

不需要調用sendComplete

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

        [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ù)據
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ù)據
2017-07-28 16:46:06.472 RAC_learning[3563:202620] hello B

(4)zipWith

把兩個信號壓縮成一個信號,只有當兩個信號同時發(fā)出信號內容時礁竞,并且把兩個信號的內容合并成一個==元組==(RACTuple)糖荒,才會觸發(fā)壓縮流的next事件

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

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

(5)combineLatest

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

(6)reduce

用于信號發(fā)出的內容是元組寂嘉,把信號發(fā)出元組的值聚合成一個值

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ù)據:%@",x);
//    }];
    
    //使登錄按鈕在用戶名和密碼框都有數(shù)據的時候才會調用
    RAC(self.loginButton, enabled) = signal;

4奏瞬、ReactiveCocoa操作方法之過濾

(1)filter

過濾信號,使用它可以獲取滿足條件的信號

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

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

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

(2)ignore

忽略完某些值的信號.

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

(3)distinctUntilChanged

當上一次的值和當前的值有明顯的變化就會發(fā)出信號泉孩,否則會被忽略掉

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

(4)take

從開始一共取N次的信號

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

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

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

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

[signal sendNext:@2];

(5)takeLast

取最后N次的信號
==前提條件==:訂閱者必須調用完成珍昨,因為只有完成,就知道總共有多少信號
==注意==:一定要調用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

獲取信號直到執(zhí)行完這個信號

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)聽文本框的改變镣典,直到當前對象被銷毀
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];

(7)skip:(NSUInteger)

跳過幾個信號,不接受

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

5、ReactiveCocoa操作方法之秩序

doNext: 執(zhí)行Next之前唾琼,會先執(zhí)行這個Block

doCompleted: 執(zhí)行sendCompleted之前兄春,會先執(zhí)行這個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: 內容傳遞切換到制定線程中锡溯,副作用在原來線程中,把在創(chuàng)建信號時block中的代碼稱之為副作用赶舆。

subscribeOn: 內容傳遞和副作用都會切換到制定線程中。

7祭饭、ReactiveCocoa操作方法之時間

(1)timeout

超時芜茵,可以讓一個信號在一定的時間后,自動報錯

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秒后會自動調用
        NSLog(@"%@",error);
    }];

(2)interval

定時倡蝙,每隔一段時間發(fā)出信號

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操作方法之重復

(1)retry重試

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

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

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

        return nil;

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

        NSLog(@"%@",x);

    } error:^(NSError *error) {


    }];

(2)replay重放

當一個信號被多次訂閱,反復播放內容

RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    //只會進入這個block一次寺鸥,不會反復進入

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

        return nil;
    }] replay];

    [signal subscribeNext:^(id x) {

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

    }];

    [signal subscribeNext:^(id x) {

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

    }];

(3)throttle節(jié)流

當某個信號發(fā)送比較頻繁時猪钮,可以使用節(jié)流,在某一段時間不發(fā)送信號內容析既,過了一段時間獲取信號的最新內容發(fā)出躬贡。
R

ACSubject *signal = [RACSubject subject];

    _signal = signal;

    // 節(jié)流谆奥,在一定時間(1秒)內眼坏,不接收任何信號內容,過了這個時間(1秒)獲取最后發(fā)送的信號內容發(fā)出酸些。
    [[signal throttle:1] subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末宰译,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子魄懂,更是在濱河造成了極大的恐慌沿侈,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件市栗,死亡現(xiàn)場離奇詭異缀拭,居然都是意外死亡咳短,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門蛛淋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咙好,“玉大人,你說我怎么就攤上這事褐荷」葱В” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵叛甫,是天一觀的道長层宫。 經常有香客問我,道長其监,這世上最難降的妖魔是什么萌腿? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮抖苦,結果婚禮上哮奇,老公的妹妹穿的比我還像新娘。我一直安慰自己睛约,他們只是感情好鼎俘,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辩涝,像睡著了一般贸伐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怔揩,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天捉邢,我揣著相機與錄音,去河邊找鬼商膊。 笑死伏伐,一個胖子當著我的面吹牛,可吹牛的內容都是我干的晕拆。 我是一名探鬼主播藐翎,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼实幕!你這毒婦竟也來了吝镣?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤昆庇,失蹤者是張志新(化名)和其女友劉穎末贾,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體整吆,經...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡拱撵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年辉川,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拴测。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡员串,死狀恐怖,靈堂內的尸體忽然破棺而出昼扛,到底是詐尸還是另有隱情寸齐,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布抄谐,位于F島的核電站渺鹦,受9級特大地震影響,放射性物質發(fā)生泄漏蛹含。R本人自食惡果不足惜毅厚,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浦箱。 院中可真熱鬧吸耿,春花似錦、人聲如沸酷窥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓬推。三九已至妆棒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沸伏,已是汗流浹背糕珊。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毅糟,地道東北人红选。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像姆另,于是被迫代替她去往敵國和親喇肋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內容