美文网首页
iOS_RAC进阶学习

iOS_RAC进阶学习

作者: MR_詹 | 来源:发表于2020-11-16 17:41 被阅读0次

一、信号合并

(1)信号合并_Merge

/// 【多个信号合并】- 1
/// 只要其中一个信号有信号,就会触发
/// 场景:适合多个事件的处理流程相同。比如有多个按钮的触发事件都是跳转下一页
-(void)merge {
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    RACSubject * signalC = [RACSubject subject];
    
    ///两个信号组合信号
    RACSignal * mergeSignal = [signalA merge:signalB];
    [mergeSignal subscribeNext:^(id x) {
       NSLog(@"%@",x);
    }];
    
    /// 多个信号组合
    RACSignal * mulitSignal = [RACSignal merge:@[signalA,signalB,signalC]];
    [mulitSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"mergeSignal : %@",x);
    }];
    
    /// 发送信号---交换位置则数据结果顺序也会交换
    [signalC sendNext:@3];
    [signalB sendNext:@2];
    [signalA sendNext:@1];
}

(2)信号合并_CombineLatest

/// 【多个信号合并】- 2
/// 将多个信号合成一个信号,只有每个信号都触发过,才会合成一个信号触发
/// 场景:在需要满足某种条件下,才能执行下一步。比如登录,只有输入账号密码,之后才能提交
/// 备注:还有另外一个常用方法:combineLatest:reduce:
- (void)combineLatest {
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    RACSubject * signalC = [RACSubject subject];
    
    /**
         [[RACSignal combineLatest:@[signalA,signalB,signalC]] subscribeNext:^(RACTuple * _Nullable x) {
             NSNumber *a = x.first;
             NSNumber *b = x.second;
             NSString *c = x.third;
             NSLog(@"最终结果:a:%@,b:%@,c:%@",a,b,c);
         }];
     */
    
    [[RACSignal combineLatest:@[signalA,signalB,signalC] reduce:^id _Nonnull(NSNumber *a,NSNumber *b,NSString *c){
        /// reduce可以将合并后的信号RACTuple元祖的值都取出来,
        /// 然后做一些操作,再合成一个另外一个值返回出去
        NSString *resutl = [NSString stringWithFormat:@"最终结果:a:%@,b:%@,c:%@",a,b,c];
        return resutl;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [signalC sendNext:@"3"];
    [signalB sendNext:@2];
    [signalA sendNext:@1];
}

(3)信号合并_concat

/// 【多个信号合并】- 3
///  按顺序拼接信号,按顺序接收信号,必须等上一个信号完成sendCompleted,下个信号才有用。类似于同步
/// 场景:信号之间有依赖关系的。比如下载解压,只有下载成功后才能解压
- (void)concat {
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    
    [signalA subscribeNext:^(id  _Nullable x) {
        [signalA sendCompleted];
    }];
    
    [signalB subscribeNext:^(id  _Nullable x) {
        
    }];
    
    /// 必须singnalA信号sendCompleted之后,才能接收signalB 的信号
    [[signalA concat:signalB] subscribeNext:^(id  _Nullable x) {
        NSLog(@"下载解压完成");
    }];
    
    /// 打印结果:下载解压完成
    [signalA sendNext:@"下载"];
    [signalB sendNext:@"解压"];
    
    /// 打印结果为空
    /// [signalB sendNext:@"解压"];
    /// [signalA sendNext:@"下载"];
    
}

(4)信号合并_then

/// 【多个信号合并】- 4
///  按顺序拼接信号,按顺序接收,必须等上一个信号完成sendCompleted,下个信号才有用。
///  与concat功能类似,多了第一个信号完成后能额外执行其他代码,再出发第二个信号
///  场景:信号之间有依赖关系的。比如下载解压
- (void)then {
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    
    [signalA subscribeNext:^(id  _Nullable x) {
        [signalA sendCompleted];
    }];
    
    [signalB subscribeNext:^(id  _Nullable x) {
        
    }];
    
    /// 必须singnalA信号sendCompleted之后,才能接收signalB 的信号
    [[signalA then:^RACSignal * _Nonnull{
        NSLog(@"下载完成,数据拼接");
        return signalB;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"下载解压完成");
    }];
    
    /// 打印结果:
    /// 下载完成,数据拼接
    /// 下载解压完成
    [signalA sendNext:@"下载"];
    [signalB sendNext:@"解压"];
    
    /// 打印结果:下载完成,数据拼接
    /// [signalB sendNext:@"解压"];
    /// [signalA sendNext:@"下载"];
    
}

(4)信号合并_zipWith

/// 【多个信号合并】- 5
///  把两个信号压缩成一个信号,只有当两个信号同时发出信号时,将两个信号的内容合并成一个元祖,触发压缩信号
///  与combineLatest作用类似
///  场景:在需要满足某种条件下,才能执行下一步。比如当一个界面有多个请求的时候,要等所有请求完成才能更新UI
- (void)zipWith {
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];

    RACSignal * zipSignale = [signalA zipWith:signalB];
    [zipSignale subscribeNext:^(RACTuple *x) {
        NSLog(@"下载解压完成:%@ %@",x.first,x.second);
    }];
   
    /// 打印结果:
    /// 下载完成,数据拼接
    /// 下载解压完成
    [signalA sendNext:@"下载"];
    [signalB sendNext:@"解压"];
}

(5)信号合并_liftSelector

/// 【多个信号合并】- 6
/// 当信号组的每个信号都发送过信号(sendNext:才算,而sendError:不算),就会触发关联的方法selector;
/// 信号数组的个数与selector的参数数量一一对应
/// 场景:一个界面有多个接口,需要都获取数据后,才刷新界面
- (void)liftSelector {
    RACSubject * signalA = [RACSubject subject];
    RACSubject * signalB = [RACSubject subject];
    RACSubject * signalC = [RACSubject subject];
    
    [self rac_liftSelector:@selector(receiveSignalValuesWithR1:r2:r3:) withSignalsFromArray:@[signalA,signalB,signalC]];

    [signalA sendNext:@(1)];
    [signalB sendNext:@(2)];
    [signalC sendNext:@(3)];
}

- (void)receiveSignalValuesWithR1:(id)data1 r2:(id)data2 r3:(id)data3 {
    NSLog(@"r1:%@ r2:%@ r3:%@",data1,data2,data3);
}

二、信号过滤

(1)信号过滤_skip

/// 【信号过滤】- 1
///  跳过前面N次信号
- (void)skip {
    RACSubject *signal = [RACSubject subject];
    
    /// 跳过第一次的信号
    [[signal skip:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [signal sendNext:@(1)];
    [signal sendNext:@(2)];
    [signal sendNext:@(3)];
    [signal sendNext:@(4)];
}

(2)信号过滤_take

/// 【信号过滤】- 2
///  只执行前面N次信号,此后的都不执行
///  与skip相反
- (void)take {
    RACSubject *signal = [RACSubject subject];
    
    /// 只执行第一次的信号
    [[signal take:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [signal sendNext:@(1)];
    [signal sendNext:@(2)];
    [signal sendNext:@(3)];
    [signal sendNext:@(4)];
}

(3)信号过滤_ takeLast

/// 【信号过滤】- 3
///  执行最后N次的信号,前提是订阅者必须调用sendCompleted,这样才能知道总共有多少个信号
- (void)takeLast {
    RACSubject *signal = [RACSubject subject];
    
    /// 只执行最后一次的信号
    [[signal takeLast:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [signal sendNext:@(1)];
    [signal sendNext:@(2)];
    [signal sendNext:@(3)];
    [signal sendNext:@(4)];
    [signal sendCompleted];
}

(4)信号过滤_ takeUntil

/// 【信号过滤】- 4
///  直到某个信号被触发,不再监听
- (void)takeUntil {
    RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];
    
    /// 如果signalB信号触发了,那么signalA将不再执行
    [[signalA takeUntil:signalB] subscribeNext:^(id  _Nullable x) {
        NSLog(@"signal A 执行了");
    }];
    
    [signalA sendNext:nil];
    [signalB sendNext:nil];
    [signalA sendNext:nil];
}

(5)信号过滤_ ignore

/// 【信号过滤】- 5
///  忽略信号,忽略掉规定的值
- (void)ignore {
    RACSubject *signal = [RACSubject subject];
    
    /// 忽略@(3)这个值
    [[signal ignore:@(3)] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [signal sendNext:@(1)];
    [signal sendNext:@(2)];
    [signal sendNext:@(3)];
    [signal sendNext:@(4)];

}

(6)信号过滤_ filter

/// 【信号过滤】- 6
///  过滤信号,只返回满足条件的信号
- (void)filter {
    RACSubject *signal = [RACSubject subject];
    
    [[signal filter:^BOOL(NSNumber *value) {
        /// 筛选条件
        /// 只有满足筛选条件的,返回YES,才会到下面的信号
        if (value.intValue > 2) {
            return YES;
        }else{
            return NO;
        }
    }] subscribeNext:^(id  _Nullable x) {
        /// 满足筛选条件的信号,会转到这里
        NSLog(@"%@",x);
    }];;
    
    [signal sendNext:@(1)];
    [signal sendNext:@(2)];
    [signal sendNext:@(3)];
    [signal sendNext:@(4)];

}

(7)信号过滤_ distinctUntilChanged

/// 【信号过滤】- 7
///  监听信号内容的变化,只有发生变化才会触发
///  在UI控件刷新用的比较多
- (void)distinctUntilChanged {
    RACSubject *signal = [RACSubject subject];
    
    [[signal distinctUntilChanged] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    [signal sendNext:@(1)];
    [signal sendNext:@(2)];
    [signal sendNext:@(3)];
    [signal sendNext:@(3)]; /// 与上一个信号内容相同,因此被忽略了
    [signal sendNext:@(4)];
    [signal sendNext:@(3)];

}

三、信号映射

信号映射_map

/// 【信号映射
/// 把源信号的值映射成一个新的值
- (void)map {
    RACSubject *signal = [RACSubject subject];
    
    RACSignal *mapSignal = [signal map:^id _Nullable(id  _Nullable value) {
        return [NSString stringWithFormat:@"处理【%@】",value];
    }];
    
    [mapSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"最终接受到的值:%@",x);
    }];
    
    [signal sendNext:@"源信号"];
}

四、定时器

(1)定时器_delay

/// 【定时器】- 1
/// 延迟多少秒执行
- (void)delay {
    RACSubject *signal = [RACSubject subject];
    
    [[signal delay:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"延迟2秒执行");
    }];
    
    NSLog(@"开始发送信号");
    [signal sendNext:nil];
}

(2)定时器_afterDelay

/// 【定时器】- 2
/// 延迟多少秒执行
- (void)afterDelay {
    NSLog(@"开始");
    [[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
}
image.png

(3)定时器_delay

/// 【定时器】- 3
/// 间隔多少秒,循环执行
- (void)interval {
    /// 备注:
    /// 最好添加一个定时器结束的事件,比如viewcontroller销毁信号,
    /// 这样定时器就不会在界面销毁了还在一直执行
    [[[RACSignal interval:1 onScheduler:[RACScheduler scheduler]] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"每秒执行一次");
    }];
}

五、重试

/// 只要失败,就会重新执行创建信号中的block,直到成功
- (void)retry {
    RACSignal *retrySignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        static int a = 1;
        if (a > 3) {
            [subscriber sendNext:@(a)];
        }else{
            [subscriber sendError:nil];
        }
        a++;
        return nil;
    }] retry];
    
    
    [retrySignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"最终结果:%@",x);
    }];
}

六、重放

/// 当一个信号被多次订阅,反复播放内容
- (void)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);
    }];
}

七、执行顺序

/// doNext 、doComplete、doError
- (void)order {
    RACSignal *signal = [[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"我被订阅了");
        [subscriber sendNext:@"0"];
        [subscriber sendCompleted];
        return nil;
    }]doNext:^(id  _Nullable x) {
        /// 在sendNext:前执行
        NSLog(@"doNext:");
    }]doCompleted:^{
        /// 在sendCompleted:前执行
        NSLog(@"doComplete:");
    }]doError:^(NSError * _Nonnull error) {
        /// 在sendError:前执行
        NSLog(@"doError:");
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
}

八、节流

/// 某个时间内只获取最后一次的信号
- (void)throttle {
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.frame = CGRectMake(0,200, self.view.frame.size.width, 300);
    btn.backgroundColor = UIColor.grayColor;
    [self.view addSubview:btn];
    
    /// 可以避免按钮多次点击误触发事件
    /// 0.5 是指从连续点击的最后一次点击开始计算,0.5秒触发点击事件,
    /// 如果0.5秒内还有点击,则从最后一次开始重新计时
    [[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] throttle:0.5] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"%@",x);
    }];
}

完整DEMO
链接: https://pan.baidu.com/s/15zyu0_daautlYjaCg6lwJA 密码: h14n

相关文章

  • iOS_RAC进阶学习

    一、信号合并 (1)信号合并_Merge (2)信号合并_CombineLatest (3)信号合并_concat...

  • 学习图谱

    前端整体 基础学习路线 进阶学习路线 整体学习路线 「前端进阶」2018/2019 史上最全的前端学习路线 How...

  • Python 中一些容易忽略的知识点(2)

    最近在补 Python 进阶的内容,学习资源来自:Python 进阶,是《Intermediate Python》...

  • Python 中一些容易忽略的知识点(1)

    最近在补 Python 进阶的内容,学习资源来自:Python 进阶,是《Intermediate Python》...

  • JavaScript学习笔记(五)

    慕课网JavaScript进阶篇第9章学习笔记 JavaScript进阶篇—第9章 JavaScript学习笔记(...

  • Java进阶

    注:采转归档,自己学习查询使用 Java进阶01 String类Java进阶02 异常处理Java进阶03 IO基...

  • 进阶课毕业感言

    进阶课结语:紧张、刺激、高学习效率的股票进阶课即将拉上帷幕了,刚开始的我是根据股票初级课的习惯和态度学习进阶课的(...

  • 【连载】内识进阶——简介2/2

    如何与进阶协作? 为了使你从内识进阶的学习中获得最大的效果,请考虑以下的建议: *内识进阶是一套完整的学习计划。每...

  • T2第一天

    今天学习了希沃交互式课件授课进阶技巧,学习了蒙层进阶玩法,拖拉,思维导图进阶玩法,无限克隆,受益匪浅,我也进行了实...

  • 2017-07-03

    webpack更好配置 webpack进阶-知乎 webpack 学习 nodejs 学习

网友评论

      本文标题:iOS_RAC进阶学习

      本文链接:https://www.haomeiwen.com/subject/meqbbktx.html