RAC_6.终结篇

6 RAC终结篇

6.1 映射

RAC的映射主要有两个方法(flattenMap map),这两个方法主要用于将信号源的内容映射成为一个新的信号。

  • flattenMap
    它其实也是绑定信号,一般用于信号中的信号。
    RACSubject *subject = [RACSubject subject];
   
   RACSignal *signal = [subject flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
       value = [NSString stringWithFormat:@"处理数据:%@",value];
       //返回信号用来包装修改过的内容
       return [RACReturnSignal return:value];
   }];
   
   //订阅绑定信号
   [signal subscribeNext:^(id  _Nullable x) {
       NSLog(@"%@",x);
   }];
   
   //发送数据
   [subject sendNext:@"123"];

运行如图:

image

看起来有点绕,说白了我们在什么场景下会用到这种呢?

就在我们发送的数据,需要对数据进行处理然后再订阅这个信号的时候就可以使用这种方式,其实跟我们上一节中提到的bind是一样的。

  • map

这个方法跟flattenMap稍微有一点不同,他的block返回值是一个id类型,而flattenMap是一个信号。

也就是说不用在返回信号了,直接返回一个数据,返回的数据就是处理后的数据。

    RACSubject *subject = [RACSubject subject];
    
    RACSignal *signal = [subject map:^id _Nullable(id  _Nullable value) {
        //返回的数据就是需要处理的数据
        return [NSString stringWithFormat:@"%@123",value];
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    //发送数据
    [subject sendNext:@"我想静静"];

运行如图:


image

6.2 组合

concat:按顺序组合。
刚刚我们说到了rac_liftSelector的使用场景,它是在等多个信号全部都返回数据后再刷新UI。那么我们现在有一个需求,就是按顺序刷新UI,也就是说你这些接口什么时候请求完数据我并不知道,但是你请求完成后的处理要按照我的顺序来。处理完第一个,再处理第二个。

    //组合!!
    //创建信号!!
    RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"发送请求A");
        //发送数据
        [subscriber sendNext:@"数据A"];
        //哥么结束了!!
        [subscriber sendCompleted];
        //[subscriber sendError:nil];
        return nil;
    }];
    
    RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"发送请求B");
        //发送数据
        [subscriber sendNext:@"数据B"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal * signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"发送请求C");
        //发送数据
        [subscriber sendNext:@"数据C"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    //concat:按顺序组合!!
    //创建组合信号!!
    RACSignal * concatSignal = [RACSignal concat:@[signalA,signalB,signalC]];
    
    //订阅组合信号
    [concatSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

运行如图:


image

then:

忽略掉前面一个信号所有的值,返回后一个信号的数据。也就是说后一个信号的数据要依赖前一个信号的发送完毕,但我并不需要处理前一个信号的数据。

    //创建信号!!
    RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"发送请求A");
        //发送数据
        [subscriber sendNext:@"数据A"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"发送请求B");
        //发送数据
        [subscriber sendNext:@"数据B"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    //then:忽略掉第一个信号所有的值!!
    RACSignal * thenSignal = [signalA then:^RACSignal * _Nonnull{
        return signalB;
    }];
    
    //订阅信号
    [thenSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

运行如图:


image

merge: 无序组合,谁先发送谁先处理。

前面我说到的都是有序的,那么肯定也有无序的组合,假设我们一般页面有N多个接口的请求,需要来一个就显示一个。处理的代码呢也能写到一起。

    //创建信号
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    RACSubject * signalC = [RACSubject subject];
    
    //组合信号
    RACSignal * mergeSignal = [RACSignal merge:@[signalA,signalB,signalC]];
    
    //订阅 -- 根据发送的情况接受数据!!
    [mergeSignal subscribeNext:^(id  _Nullable x) {
        //任意一二信号发送内容就会来这个Block
        NSLog(@"%@",x);
    }];
    
    //发送数据
    [signalC sendNext:@"数据C"];
    [signalA sendNext:@"数据A"];
    [signalB sendNext:@"数据B"];

运行如图:


image

zipWith:

两个信号压缩!只有当两个信号同时发出信号内容,并且将内容合并成为一个元祖给你

    //创建信号
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    
    //压缩
    RACSignal * zipSignal =  [signalA zipWith:signalB];
    
    //接受数据  和发送顺序无关!!
    [zipSignal subscribeNext:^(id  _Nullable x) {
        RACTupleUnpack(NSString *str1,NSString *str2) = x;
        NSLog(@"str1=%@,str2=%@",str1,str2);
    }];
    //发送数据
    //这是一组
    [signalB sendNext:@"小明"];
    [signalA sendNext:@"小小"];
    //这也是一组
    [signalB sendNext:@"小明1"];
    [signalA sendNext:@"小小1"];
    //这也是一组
    [signalB sendNext:@"小明2"];
    [signalA sendNext:@"小小2"];

运行如图:

image

这里 只有signalAsignalB同时发送了一次信号,才会接收到信号,接收到的数据是一个元祖,值就是signalAsignalB发送的数据。

元祖的数据顺序和你发送的顺序无关,而是和[signalA zipWith:signalB]这个方法有关。

combineLatest: reduce:

组合信号,将多个信号的数据进行合并处理,在返回一个数据给新的信号。

这个东西呢,我们我们通过一个例子来说明,就拿一个简单的登录来说把。

首先呢有两个输入框(UITextField),账号和密码,还有一个按钮(UIButton),首先这个按钮是不可点击的,当两个输入框都有值的情况下呢按钮才可以点击。

 UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
    [self.view addSubview:nameTF];
    nameTF.placeholder = @"请出入昵称";
    nameTF.backgroundColor = [UIColor yellowColor];
    
    UITextField *pwdTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 120, 200, 50)];
    [self.view addSubview:pwdTF];
    pwdTF.placeholder = @"请出入密码";
    pwdTF.backgroundColor = [UIColor grayColor];
    
    UIButton *loginBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 180, 100, 50)];
    [self.view addSubview:loginBtn];
    [loginBtn setTitle:@"登录" forState:UIControlStateNormal];
    [loginBtn setBackgroundColor:[UIColor purpleColor]];
    RACSignal *signalBtn = [loginBtn rac_signalForControlEvents:(UIControlEventTouchUpInside)];
    [signalBtn subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    //组合
    //reduceBlock参数:根据组合的信号关联的  必须一一对应!!
    RACSignal * signal = [RACSignal combineLatest:@[nameTF.rac_textSignal,pwdTF.rac_textSignal] reduce:^id _Nullable(NSString *nickName,NSString * pwd){
        
        //两个文本框的text是否有值!!
        return @(nickName.length && pwd.length);
    }];
    RAC(loginBtn,enabled) = signal;

运行如图:


image

6.3 过滤

  • filter: 当满足特定的条件,才能获取到订阅的信号数据。
    UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
    [self.view addSubview:nameTF];
    nameTF.backgroundColor = [UIColor yellowColor];
    
    RACSignal *signal = [nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
        if (value.length > 5) {
            return YES;
        }
        return nil;
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

运行如图:


image
  • ignore:忽略掉哪些值。
    UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
    [self.view addSubview:nameTF];
    nameTF.backgroundColor = [UIColor yellowColor];
    
    RACSignal *signal = [nameTF.rac_textSignal ignore:@"a"];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

运行如图:

输入第一个a并没有监听到

image
  • take: 指定拿前面的哪几条数据!!(从前往后)
    RACSubject * subject = [RACSubject subject];
    
    //take:指定拿前面的哪几条数据!!(从前往后)
    //takeLast:指定拿后面的哪几条数据!!(从后往前)注意点:一定要写结束!!
    [[subject take:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@"2"];
    [subject sendNext:@"3"];
    [subject sendNext:@"1"];
    [subject sendCompleted];

运行如图:

image

  • takeLast: 指定拿后面的哪几条数据!!(从后往前)注意点:一定要写结束!!
    RACSubject * subject = [RACSubject subject];
    
    //take:指定拿前面的哪几条数据!!(从前往后)
    //takeLast:指定拿后面的哪几条数据!!(从后往前)注意点:一定要写结束!!
    [[subject takeLast:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@"2"];
    [subject sendNext:@"3"];
    [subject sendNext:@"1"];
    [subject sendCompleted];

运行如图:

image

  • takeUntil:直到你的标记信号发送数据的时候结束!!!
    RACSubject * subject = [RACSubject subject];
    //专门做一个标记信号!!
    RACSubject * signal = [RACSubject subject];
    
    //takeUntil:直到你的标记信号发送数据的时候结束!!!
    [[subject takeUntil:signal] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    
    [subject sendNext:@"2"];
    [subject sendNext:@"静静"];
    [signal sendNext:@"小明"];//这个信号发送之后就结束了。
//    [signal sendCompleted];//标记信号!! 这个信号发送之后也一样结束。
    
    [subject sendNext:@"3"];
    [subject sendNext:@"1"];
    [subject sendCompleted];

当signal发送信号后,subject的发送就会结束,这里的 3 1 就不会在发送了。这种方式也比较常用。

运行如图:

image

  • distinct:忽略掉重复数据
//1.创建信号
    RACSubject * subject = [RACSubject subject];
    
    //忽略掉重复数据
    [[subject distinctUntilChanged] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    //发送
    [subject sendNext:@"小明"];
    [subject sendNext:@"小明"];
    [subject sendNext:@"小小"];
    [subject sendNext:@"小爱"];

运行如图:

image

这样可以吧。。我们换个顺序好了

看图:

image

依旧是两个小明,不太靠谱吧

  • skip: 跳跃几个值
    RACSubject * subject = [RACSubject subject];
    
    //skip: 跳跃几个值
    [[subject skip:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [subject sendNext:@"小明"];
    [subject sendNext:@"小小"];
    [subject sendNext:@"小红帽"];
    [subject sendNext:@"小爱"];
    [subject sendNext:@"小不点"];
    [subject sendNext:@"大灰狼"];

运行如图:


image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,585评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,923评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,314评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,346评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,718评论 3 291
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,828评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,020评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,758评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,486评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,722评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,196评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,546评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,211评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,132评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,916评论 0 200
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,904评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,758评论 2 274

推荐阅读更多精彩内容