iOS OCReactiveObjCRAC

iOS开发之RAC(二)进阶篇

2018-01-16  本文已影响703人  赤小豆nil

初级篇简单的介绍了RAC。本文将介绍RAC在项目中常见的类和最常用的一些操作方法!!!

一、常见类

1、RACSiganl :信号类。

2、RACSubscriber :订阅者

3、RACDisposable :用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。

4、RACSubject :信号提供者,自己可以充当信号,又能发送信号。

5、RACTuple :元组类,类似NSArray,用来包装值.

6、RACSequence: RAC中的集合类

7、RACCommand: RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。

8、RACMulticastConnection :用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理。

9、RACScheduler: RAC中的队列,用GCD封装的。



二、常见操作

1、 combineLatest:把多个信号合并成一个信号,而且需要每个信号都sendNext一次,才会触发这个合并的信号!!

    UITextField *nameTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 100, 300, 40)];
    nameTextField.borderStyle = UITextBorderStyleRoundedRect;
    [self.view addSubview:nameTextField];
    
    UITextField *pwdTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 140, 300, 40)];
    pwdTextField.borderStyle = UITextBorderStyleRoundedRect;
    [self.view addSubview:pwdTextField];
    
    UIButton *addBtn = [UIButton buttonWithType:UIButtonTypeContactAdd];
    addBtn.center = self.view.center;
    [self.view addSubview:addBtn];
    RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];

//    combineLatest 把多个信号捆綁成一个信号,最多不要超过五个
//    RACTuple 元组,可以像是一个字典,里面可以放多中类型
    [[RACSignal combineLatest:@[nameTextField.rac_textSignal, pwdTextField.rac_textSignal ,signalBtn]] subscribeNext:^(RACTuple * _Nullable x) {
        NSLog(@"%@",x);
  
    }];

上面监听了两个文本框,一个按钮。如果不触发按钮的点击事件,那么NSLog(@"%@",x);将永远无法打印出来,上面说了必须每个信号都sendNext一次,才会触发这个合并的信号!!

因为是多个信号合并出一个信号,返回的值里就包含多个信号的值。取值:

    [[RACSignal combineLatest:@[nameTextField.rac_textSignal, pwdTextField.rac_textSignal ,signalBtn]] subscribeNext:^(RACTuple * _Nullable x) {
        NSString *name = x.first;
        NSString *pwd = x.second;
        UIButton *btn = x.third;
        NSLog(@"%@ %@ %@",name,pwd,btn);
    }];

顺序是按你放进去的信号顺序排序的,返回值RACTuple叫元组,可以自己点进去看看这个东西,不多做解释了!!


2、reduce:把元祖里的值分别都取出来,然后对这些值做一些操作,再合成一个值返回出去。

image.png

上面这段代码,可用于登录时的操作,监听两个文本框的值,如果都有值,返回的BOOL值可以给按钮,让按钮变成可点击状态。如果不满足条件,则不可点击!!!


3、 map:映射,取到监听后的值,映射成一个新值,返回出去!!

    [[[nameTextField rac_textSignal] map:^id _Nullable(NSString * _Nullable value) {
        
        return @(value.length > 0);
        
    }] subscribeNext:^(id  _Nullable x) {
        
        pwdTextField.hidden = [x boolValue];
        
    }];

开发中,如果信号发出的值不是信号,映射一般使用Map


4、 flattenMap:映射,取到信号源的值,映射成一个新的信号,返回出去!!

    [[[nameTextField rac_textSignal] flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
        
        value = [NSString stringWithFormat:@"数据处理: %@",value];
        
        return [RACReturnSignal return:value];
        
    }] subscribeNext:^(id  _Nullable x) {
        
        NSLog(@"%@",x);
        
    }];

开发中,如果信号发出的值是信号,映射就使用FlatternMap


5、merge:捆绑法,不分先后。

    [[[nameTextField rac_textSignal] merge:[pwdTextField rac_textSignal]] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

把多个信号捆绑在一起,任何一个信号有新值都会触发这个捆绑的信号!谁触发的信号,就拿到谁的值!!


6、take:从开始一共取N次的信号

    RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
    [[signalBtn take:3] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

你点击按钮的前三次,都会有打印,第四次开始就不会再打印了。


7、takeLast:取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号,然后取最后N次的信号!!

    RACSubject * subject = [RACSubject subject];
    [[subject takeLast:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    [subject sendNext:@"one"];
    [subject sendNext:@"two"];
    [subject sendNext:@"three"];
    [subject sendCompleted];

只会打印three,取的是最后一次的信号!!!
RACSubject既可以作为信号,又可以发送信号!!!


8、filter:过滤信号,return 满足条件的信号。

    [[[nameTextField rac_textSignal] filter:^BOOL(NSString * _Nullable value) {
        return [value integerValue] % 2 == 0;
    }] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);
    }];

输入框内只有你输入满足条件的数字才会被打印出来!!!


9、ignore:忽略信号,忽略掉你规定的值。

    [[[nameTextField rac_textSignal] ignore:@"3"] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);
    }];

输入框出现“3”将不被打印!!!内部还是调用filter来实现的。


10、distinctUntilChanged:监听的值有明显变化时,才会发出信号。

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

UI刷新的时候,用的最多。


11、concat:按顺序拼接信号,按顺序接收信号,但是必须等上一个信号完成,下一个信号才有用!!!

    [[[nameTextField rac_textSignal] concat:[pwdTextField rac_textSignal]] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
        //永远不会打印,有关pwdTextField的值,因为前面的信号,没有调用sendCompleted。
    }];

下面正确使用

    RACSignal *signalOne = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"下载"];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signalTwo = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"解压"];
        return nil;
    }];
    [[signalOne concat:signalTwo] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
        //先打印下载,后打印解压
    }];

可用于两个网络请求的数据之间有依赖关系!!!


12、then:也是拼接信号,一样需要前面的信号调用sendCompleted,才会发送信号。

    RACSignal *signalOne = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"下载"];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signalTwo = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"解压"];
        return nil;
    }];
   
    [[signalOne then:^RACSignal * _Nonnull{
        return signalTwo;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

然而他永远不会打印“下载”,只会打印拼接在最后的一个信号!!!


13、zipWith:把两个信号压缩成一个信号,且必须两个信号都触发了(同次数),才会打印。两个信号的值,会合并成一个元组。

    RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
    [[[nameTextField rac_textSignal] zipWith:signalBtn] subscribeNext:^(RACTwoTuple<NSString *,id> * _Nullable x) {
        NSLog(@"%@",x);
    }];

输入框触发了三次后,点击一下按钮,就会打印出输入框第一次触发的值和按钮的值!!当按钮点击四次后,不会有打印。必须再次触发输入框的信号,就会打印出,输入框第四次触发信号的值和第四次按钮时的各种状态。(说不清,自己去试一下吧)!!!


14、takeUntil:直到某个信号触发,不再监听。

    [[[nameTextField rac_textSignal] takeUntil:signalBtn] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"%@",x);
    }];

点击按钮以后,就再也不会打印了!!!


15、skip:跳过前面N次信号,和take相反。

    RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
    [[signalBtn skip:3] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

按钮前三次点击无打印,第四次点击以后,都会打印!!!


16、switchToLatest:用来接收信号发出的信号。

    RACSubject *Asignal = [RACSubject subject];
    RACSubject *Bsignal = [RACSubject subject];
    
    [Asignal.switchToLatest subscribeNext:^(id x) {
        //打印出 1
        NSLog(@"%@",x);
    }];
    //A发送B
    [Asignal sendNext:Bsignal];
    //B发送 1
    [Bsignal sendNext:@1];

只能用于信号发出的信号


17、doNext和doCompleted和doError:在发送信号前。

    [[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"chixiaodou"];
        [subscriber sendCompleted];
        return nil;
    }] doNext:^(id  _Nullable x) {
        //执行[subscriber sendNext:@"chixiaodou"]前会先走这个block
        NSLog(@"doNext");
    }] doCompleted:^{
        //执行[subscriber sendCompleted]前会先走这个block
        NSLog(@"doCompleted");
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

doError的栗子是一样的,就不举了。


18、interval:多少秒执行一次。

    [[RACSignal interval:1 onScheduler:[RACScheduler scheduler]] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"%@",x);
    }];

每秒都会打印现在的时间,要记得调用takeUntil来结束它,不然一直打印,直到天荒地老...

    [[[RACSignal interval:1 onScheduler:[RACScheduler scheduler]] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"%@",x);
    }];

控制器消失后就不再打印了


19、delay:延迟多少秒执行。

    [[signalBtn delay:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

点击按钮后,过2秒才打印


20、retry:重试,直到成功。

    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        static int a = 1;
        if (a > 3) {
            [subscriber sendNext:@(a)];
        }else{
            [subscriber sendError:nil];
        }
        a++;
        return nil;
        
    }] retry] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    } error:^(NSError *error) {
        
    }];

直到a=4才会打印出来


21、replay:被多次订阅后,每次都是重新执行。

    __block int a = 10;
    RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        a += 5;
        [subscriber sendNext:@(a)];
        return nil;
    }]replay];
    
    [signal subscribeNext:^(id x) {
        NSLog(@"第一个订阅者%@",x);
    }];
    
    [signal subscribeNext:^(id x) {
        NSLog(@"第二个订阅者%@",x);
    }];
    
    [signal subscribeNext:^(id x) {
        NSLog(@"第三个订阅者%@",x);
    }];

被连续三次订阅,打印出来的值都是15,说明后面的每次订阅a=10!!!如果去除replay,将会打印出15、20、25!!加上replay后,后面的订阅者都是从10开始算的!!!


22、throttle:节流,某个时间内只获取最后一次的信号。

    [[signalBtn throttle:3] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

如果一秒点了一百下按钮(单身的手速),那么再过三秒,只会打印出你第一百下点击按钮时的信号,前面的99次都不接收!!!从你不点击按钮后算三秒!!!


23、RACSequence:RAC里的集合类

    NSArray * arr = @[@(1), @(2), @(3), @(4), @(5)] ;
    RACSequence * s1 = [arr rac_sequence];
    arr = [s1 array];

可以和数组之间任意转换


24、RACChannelTerminal:用来实现双向绑定的类

    RACChannelTerminal * signalnameText = [nameTextField rac_newTextChannel];
    RACChannelTerminal * signalpwdText = [pwdTextField rac_newTextChannel];
    [signalnameText subscribe:signalpwdText];
    [signalpwdText subscribe:signalnameText];

不管怎么输入,两个输入框里的内容已经完全保持一致了!!!


25、RAC(TARGET, ...):获取某个信号的值赋给属性

    RAC(self.person,name) = nameTextField.rac_textSignal;

输入框里的值不停的变化,那么person类的name属性值,也会不停的变化!!!


26、RACObserve(TARGET, KEYPATH):监听某个类的某个属性

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

属性的值一但改变就会打印出来!!!


上面列举的基本上是比较常用的,RAC还有非常多的功能需要自己去挖掘了,而且这些功能可以任意的组合,针对不同的业务逻辑,使用不同的组合方式。因为RAC也用了链式编程思想,非常之灵活。所以说RAC的学习曲线异常的陡峭!

如果对block不太懂的,在学习RAC之前建议了解一下block

注意:使用RAC时,牢记信号三部曲,顺序不能乱!!!

美团是我知道使用RAC最多的APP,想要知道美团对RAC的了解有多少,可以去美团看技术博客:传送门

上一篇下一篇

猜你喜欢

热点阅读