RAC基礎(chǔ)篇

RAC使用函數(shù)響應(yīng)式編程的思想,將我們平時用到的按鈕點擊事件、KVO、代理、通知等等封裝起來,處理業(yè)務(wù)邏輯的代碼放到一起,使代碼更加的簡潔、高內(nèi)聚、低耦合,那么我們來看看它的具體使用。

一、RAC的基本使用

RAC和KVO
    //使用RAC來監(jiān)聽字符串myString的變化
    [RACObserve(self, myString) subscribeNext:^(id  _Nullable x) {
        
        NSLog(@"myString值發(fā)生變化后的新值:%@",x);
    }];

一句代碼就可以代替KVO,代碼和功能在一起,寫起來方便,簡單易讀。

  • RACObserve(TARGET, KEYPATH): RAC提供的宏定義,用來監(jiān)聽值的變化,返回RACSignal類型的信號,有了這個宏定義返回的信號,就可以訂閱該信號,變化后的值。
  • subscribeNext::訂閱信號,只有訂閱了信號才可以收到值的變化。
RAC和通知
    //監(jiān)聽鍵盤彈出的通知
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        //處理接收到的通知
        NSLog(@"%@",x);
    }];

rac_addObserverForName: object::也可以添加開發(fā)中自己注冊的通知,添加監(jiān)聽通知的方法,寫在NSNotificationCenter分類中。RAC中有很多的分類實現(xiàn)不同的方法。

RAC和代理
    //添加UITextFieldDelegate代理方法textFieldDidBeginEditing:信號
    [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] subscribeNext:^(RACTuple * _Nullable x) {
        //RACTuple:元組類型
        NSLog(@"%@",x);
    }];
    //實現(xiàn)代理
    self.textField.delegate = self;

rac_signalForSelector:fromProtocol:添加代理方法信號。

  • 值得注意的是,接收訂閱信號的參數(shù)是RACTuple元組類型,熟悉swift語法的話對元組類型一定不陌生,元組是把多個值組合成一個復(fù)合值。元組內(nèi)的值可以是任意類型,并不要求是相同類型。以下是上面代碼接受到信號的打印信息,可以看一下元組是什么樣子的:
<RACTuple: 0x6000018a5960> (
    <UITextField: 0x7f966fd6b3d0; frame = (72 219; 270 34); text = ''; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x60000143dce0>; layer = <CALayer: 0x600001ad9240>>,
)
UIButton
//按鈕點擊信號
    @weakify(self);//防止循環(huán)引用的問題
    [[self.myButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @strongify(self);//暫時強引用
        //接收到點擊信號的響應(yīng),
        if(self.textField.text.length == 0) {
            NSLog(@"請先輸入名稱");
        }else {
            //...
        }
    }];

rac_signalForControlEvents ::UIButton的分類方法,產(chǎn)生點擊信號。

  • 在訂閱信號中進行UI的綁定,這種思想在 MVVM+RAC的架構(gòu)中非常重要,MVVM中通過block回調(diào)可以完成ViewModelUI層數(shù)據(jù)傳遞,使用rac進行UI綁定,就可以完成UI層向ViewModel層的數(shù)據(jù)傳輸,從而實現(xiàn)雙向綁定。
UITextField
//輸入框文字改變信號
    [self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        //打印當(dāng)前textField的text
        NSLog(@"%@",x);
    }];

rac_textSignal:輸入框輸入的文字發(fā)生改變的信號,訂閱這個信號可以處理文字長度,輸入格式等。

手勢
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
    self.label.userInteractionEnabled = YES;
    [self.label addGestureRecognizer:tap];

    [tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {

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

rac_gestureSignal:手勢觸發(fā)信號。

序列 sequence

數(shù)組遍歷

    NSArray *nameArray = @[@"Niki",@"Pan",@"Ding",@"Jiao"];
    //數(shù)組遍歷
    [nameArray.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);//依次打印數(shù)組元素
    }];
NSDictionary *dict = @{@"name":@"Niki",@"age":@"18",@"number":@"999"};
    //遍歷字典
    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
       //元組類型
        NSLog(@"%@",x);
        //RACTwoTuple繼承自RACTuple,表示有兩個值的元組
        RACTwoTuple *tuple = (RACTwoTuple *)x;
        
        NSLog(@"key == %@ , value = %@",tuple[0],tuple[1]);
        
    }];

集合類型在RAC中都封裝成了序列,通過訪問rac_sequence屬性得到序列。

二、RAC中的高階函數(shù)

  1. 信號映射:mapflattenMap,把原有信號中的值映射成新的值。
  • map:方法返回依舊是一個信號RACSignal類型,如下代碼,將rac_textSignal信號中的字符串經(jīng)過map映射處理成字符串的長度。注意:mapblock中必須要返回對象類型的數(shù)據(jù)。
    [[self.passField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
        return @(value.length);
    }] subscribeNext:^(id _Nullable x) {
        NSLog(@"映射后的新值:%@",x);//輸出字符串長度
    }];
  • flattenMap:把源信號的內(nèi)容映射成一個新的信號,信號可以是任意類型。
    [[self.passField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
        //返回RACSignal類型
        return [RACReturnSignal return:@(value.length)];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"映射后的新值:%@",x);

    }];
  1. 信號過濾:filter,ignore,distinctUntilChanged
  • filter:獲取滿足條件的信號
  • ignore:內(nèi)部調(diào)用了filter,忽略掉ignore傳入的參數(shù)。
  • distinctUntilChanged:跟函數(shù)名字面意思一樣,直到值和上一次有區(qū)別才會發(fā)出信號,忽略的是和上一次值一樣的信號。經(jīng)常用于UI的刷新,值發(fā)生變化的時候才刷新。
    下面依次來看代碼示例:
//filter
    [[self.passField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
        //輸入字符串長度大于3
        return value.length > 3;
    }] subscribeNext:^(id _Nullable x) {
        //獲取到輸入字符串長度大于3的信號
        //當(dāng)輸入字符串長度大于3才會在這里打印
            NSLog(@"%@",x);
    }];
//ignore
    [[self.passField.rac_textSignal ignore:@"n"] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);//輸入n,這里收不到信號
    }];
//distinctUntilChanged
    RACSubject *subject = [RACSubject subject];
    [[subject distinctUntilChanged] subscribeNext:^(id x) {
        NSLog(@"%@", x);//收到的信號依次是a b c,第三次發(fā)送的b被忽略了
    }];
    // 發(fā)送信號
    [subject sendNext:@"a"];
    [subject sendNext:@"b"];
    [subject sendNext:@"b"];
    [subject sendNext:@"c"];
  1. 信號合并:combineLatest,reduce,merge,zipWith
  • combineLatest:將多個信號合并起來,并且拿到各個信號的最新值,必須每個合并的signal至少都有過一次sendNext,才會觸發(fā)合并的信號。
  • reduce:把combineLatest的元組聚合成一個值發(fā)送出去,相當(dāng)于對combineLatest的進一步加工,必須每個合并的signal至少都有過一次sendNext,才會觸發(fā)合并的信號。
  • merge:把多個信號合并成一個信號,任何一個信號發(fā)送數(shù)據(jù),都能監(jiān)聽到。
  • zip:把最近發(fā)出的信號包裝成元組發(fā)出。當(dāng)每個信號同事發(fā)出信號內(nèi)容,才會發(fā)出信號。
//combineLatest
    //創(chuàng)建三個信號
    RACSubject *s1 = [RACSubject subject];
    RACSubject *s2 = [RACSubject subject];
    RACSubject *s3 = [RACSubject subject];
    //合并三個信號
    RACSignal *combineSg = [RACSignal combineLatest:@[s1,s2,s3]];
    //訂閱合并信號
    [combineSg subscribeNext:^(id  _Nullable x) {
        //當(dāng)三個信號都有一次發(fā)送的時候才能收到聚合信號
       //這里收到是一個元組類型,三個元素分別為三個信號的最新值
        NSLog(@"%@",x);
    }];
    //發(fā)送信號
    [s1 sendNext:@"a"];
    [s2 sendNext:@"1"];
    [s3 sendNext:@"!"];

    [s1 sendNext:@"b"];
    [s2 sendNext:@"2"];
    [s3 sendNext:@"@"];


    [s1 sendNext:@"c"];
    [s2 sendNext:@"3"];
    [s3 sendNext:@"#"];
//reduce
    RACSubject *s1 = [RACSubject subject];
    RACSubject *s2 = [RACSubject subject];
    RACSubject *s3 = [RACSubject subject];
    
    RACSignal *reduceSg = [RACSignal combineLatest:@[s1,s2,s3] reduce:^(id value1,id value2,id value3){
        //value1 value2 value3為三個信號的最新值
        return [NSString stringWithFormat:@"%@,%@,%@",value1,value2,value3];
    }];
    //訂閱聚合信號
    [reduceSg subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    //發(fā)送信號
    [s1 sendNext:@"a"];
    [s2 sendNext:@"1"];
    [s3 sendNext:@"!"];

    [s1 sendNext:@"b"];
    [s2 sendNext:@"2"];
    [s3 sendNext:@"@"];

    [s1 sendNext:@"c"];
    [s2 sendNext:@"3"];
    [s3 sendNext:@"#"];
/*打印輸出結(jié)果,三個信號都發(fā)送一次sendNext之后才會收到第一次聚合信號
a,1,!
b,1,!
b,2,!
b,2,@
c,2,@
c,3,@
c,3,#
*/
//merge
    RACSubject *s1 = [RACSubject subject];
    RACSubject *s2 = [RACSubject subject];
    RACSubject *s3 = [RACSubject subject];
    //合并三個信號
    RACSignal *mergeSg = [RACSignal merge:@[s1,s2,s3]];
    
    [mergeSg subscribeNext:^(id  _Nullable x) {
        //收到九次信號,每次打印當(dāng)前信號最新值
        NSLog(@"%@",x);
    }];
    
    [s1 sendNext:@"a"];
    [s2 sendNext:@"1"];
    [s3 sendNext:@"!"];

    [s1 sendNext:@"b"];
    [s2 sendNext:@"2"];
    [s3 sendNext:@"@"];

    [s1 sendNext:@"c"];
    [s2 sendNext:@"3"];
    [s3 sendNext:@"#"];
//zip
    RACSubject *s1 = [RACSubject subject];
    RACSubject *s2 = [RACSubject subject];
    RACSubject *s3 = [RACSubject subject];
    
    RACSignal *zipSg = [RACSignal zip:@[s1,s2,s3]];
    
    [zipSg subscribeNext:^(id  _Nullable x) {
        /*收到兩次信號
            (  a,  1,  !,  ) (b, 3, @, )
          */
            NSLog(@"%@",x);
    }];
    
    [s1 sendNext:@"a"];
    [s2 sendNext:@"1"];
    [s3 sendNext:@"!"];

    [s1 sendNext:@"b"];
//  [s2 sendNext:@"2"];
    [s3 sendNext:@"@"];

    [s1 sendNext:@"c"];
    [s2 sendNext:@"3"];
    [s3 sendNext:@"#"];
  1. 信號連接:concat,then
  • concat:信號連接起來,按順序響應(yīng)信號。
  • then:只收到then返回的信號,之前的信號會被忽略
//concat
    RACSignal *s1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@"信號1"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *s2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@"信號2"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *contactSg = [s1 concat:s2];
    
    [contactSg subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);//依次打印 信號1 信號2
    }];
//then
    RACSignal *s1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@"信號1"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *s2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        [subscriber sendNext:@"信號2"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    [[s2 then:^RACSignal * _Nonnull{
        return s1;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);//只收到信號1,第一個信號會被忽略
    }];
  1. 信號操作時間:timeout,interval,dely
  • timeout:超時信號,超過設(shè)定時間后會收到錯誤信號
  • dely:延時發(fā)送信號
//設(shè)置signal的超時時間是2秒
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    //延時三秒發(fā)送信號
    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
        [subscriber sendNext:@"delay"];
        [subscriber sendCompleted];
    }];
    return nil;
}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]];

[signal subscribeNext:^(id x) {
    NSLog(@"%@", x);
} error:^(NSError *error) {
    NSLog(@"%@", error);//2秒后打印信息,因為發(fā)送信號延時了3秒
}];
  1. 還有其他的,持續(xù)更新。

RAC信號響應(yīng)流程

  1. 信號聲命周期:
    創(chuàng)建信號-訂閱信號-發(fā)送信號-銷毀信號
  2. 信號響應(yīng)流程分析


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

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

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