美文网首页
iOS ReacttiveObjc

iOS ReacttiveObjc

作者: Never_Yg | 来源:发表于2018-05-01 09:21 被阅读267次

    Block

    block类型:

      //block: 就是找到block装起来的代码去执行
        void(^block)(void) = ^{
            NSLog(@"block封装的代码");
        };
        // 这个block的类型是 void(^)()
        block();
    

    使用

    - (void)masonry
    {
        self.test(); //这里执行其实是执行block里面装的代码
    }
    
    //block做返回值
    - (void(^)(void))test
    {
        void (^block)(void) = ^{
            NSLog(@"执行这里的代码");
        };
        return block;
    }
    
    

    MVVM

    目的: 将UI逻辑与业务逻辑分离
    注意点:

    • View引用ViewModel, 但反过来不行
    • ViewModel引用Model, 但反过来不行

    问题: 如果view引用了ViewModel, 但ViewModel没有引用View, 那么ViewModel如何更新视图呢?

    响应式编程思想(KVO)

    链式编程思想(block做参数, block返回对象本身)

    ReactiveCocoa主要由以下四大核心组件构成

    • 信号源: [RACStream]及其子类最核心
    • 订阅者: [RACSubscriber]的实现类及其子类
    • 调度器: [RACScheduler]及其子类
    • 清洁工: [RACDisposable]及其子类

    万物皆信号

    RACSiganl

    • 只有数据改变时, 信号内部才会发出数据, 它本身不具备发送信号的能力, 而是交给内部一个订阅者去发出
    • 默认一个信号都是冷信号, 也就是值改变了,也不会触发, 只有订阅了这个信号, 这个信号才会变成热信号, 值改变才会触发
    • 不要分开订阅next, error, completed这样的话会把前面的订阅者清除掉, 应该使用直接返回这三种的订阅方法
    [requestSignal subscribeNext:^(id  _Nullable x) {
            NSLog(@"next的block");
        } error:^(NSError * _Nullable error) {
            NSLog(@"error的block");
        } completed:^{
            NSLog(@"completed的block");
        }];
    

    一个信号最好只订阅一次, 这样就没有反复创建订阅者的副作用

    // RACSignal使用步骤:
        // 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
        // 2.订阅信号,才会激活信号. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 3.发送信号 - (void)sendNext:(id)value
        
        
        // RACSignal底层实现:
        // 1.创建信号,首先把didSubscribe保存到信号中,还不会触发。
        // 2.当信号被订阅,也就是调用signal的subscribeNext:nextBlock
        // 2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中。
        // 2.1 subscribeNext内部会调用siganl的didSubscribe
        // 3.siganl的didSubscribe中调用[subscriber sendNext:@1];
        // 3.1 sendNext底层其实就是执行subscriber的nextBlock
        
        // 1.创建信号
        RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            // block调用时刻:每当有订阅者订阅信号,就会调用block。
            
            // 2.发送信号
            [subscriber sendNext:@1];
            
            // 如果不在发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号。
            [subscriber sendCompleted];
     
            return [RACDisposable disposableWithBlock:^{
                
                // block调用时刻:当信号发送完成或者发送错误,就会自动执行这个block,取消订阅信号。
                
                // 执行完Block后,当前信号就不在被订阅了。
                
                NSLog(@"信号被销毁");
                
            }];
        }];
        
        // 3.订阅信号,才会激活信号.
        [siganl subscribeNext:^(id x) {
            // block调用时刻:每当有信号发出数据,就会调用block.
            NSLog(@"接收到数据:%@",x);
        }];
    
    
    RACSubscriber(订阅者), 用于发送信号, 这是一个协议不是一个类
    RACDisposable用于取消订阅或者清理资源, 当信号发送完成或发送错误的时候, 就会自动触发它
    RACSubject: 遵循了RACsubscriber协议的RACSignal,所以自己是信号, 也可以订阅其他信号
    RACReplaySubject: RACSubject的子类, 重复提供信号, 先把发送过的信号缓存起来, 再次订阅时直接发送缓存的值

    解释: 信号类RACSignal和RACSubject都遵守先订阅再发送信号原则, 但是RACReplaySubject可以先发送信号(内部是一个数组把信号保存起来), 再订阅, 因为它会把信号缓存起来
    使用场景: 一个类要拿到多个值的时候

    // RACSubject使用步骤
        // 1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
        // 2.订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 3.发送信号 sendNext:(id)value
    
        // RACSubject:底层实现和RACSignal不一样。
        // 1.调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了。
        // 2.调用sendNext发送信号,遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。
    
        // 1.创建信号
        RACSubject *subject = [RACSubject subject];
    
        // 2.订阅信号
        [subject subscribeNext:^(id x) {
            // block调用时刻:当信号发出新值,就会调用.
            NSLog(@"第一个订阅者%@",x);
        }];
        [subject subscribeNext:^(id x) {
            // block调用时刻:当信号发出新值,就会调用.
            NSLog(@"第二个订阅者%@",x);
        }];
    
        // 3.发送信号
        [subject sendNext:@"1"];
    
    
        // RACReplaySubject使用步骤:
        // 1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
        // 2.可以先订阅信号,也可以先发送信号。
        // 2.1 订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 2.2 发送信号 sendNext:(id)value
    
        // RACReplaySubject:底层实现和RACSubject不一样。
        // 1.调用sendNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。
        // 2.调用subscribeNext订阅信号,遍历保存的所有值,一个一个调用订阅者的nextBlock
    
        // 如果想当一个信号被订阅,就重复播放之前所有值,需要先发送信号,在订阅信号。
        // 也就是先保存值,在订阅值。
    
        // 1.创建信号
        RACReplaySubject *replaySubject = [RACReplaySubject subject];
    
        // 2.发送信号
        [replaySubject sendNext:@1];
        [replaySubject sendNext:@2];
    
        // 3.订阅信号
        [replaySubject subscribeNext:^(id x) {
    
            NSLog(@"第一个订阅者接收到的数据%@",x);
        }];
    
        // 订阅信号
        [replaySubject subscribeNext:^(id x) {
    
            NSLog(@"第二个订阅者接收到的数据%@",x);
        }];
    
    
    RACTuple: 类似NSArray, 用来包装值
    RACSequence: RAC中的集合类, 用于代替NSArray, NSDictionary, 可以使用它来快速来便利数组和字典

    注意RACSequence会开启子线程, 要在completed做U更新

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

    使用场景: 按钮点击, 网络请求

    //RACCommand控制按钮点击
        _nextBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
            //command的block
            NSLog(@"点击了按钮---%@", input);
            return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
                //信号block
                [subscriber sendNext:@"需要传出去的数据"];
                return nil;
            }];
        }];
        
        //监听
        [_nextBtn.rac_command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    RACCommand用来控制按钮是否可以点击

    //用来控制能否点击的信号
        RACSubject *enableSignal = [RACSubject subject];
        
        _nextBtn.rac_command = [[RACCommand alloc] initWithEnabled:enableSignal signalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
            //command的block
            NSLog(@"点击了按钮---%@", input);
            return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
                //信号block
                [subscriber sendNext:@"需要传出去的数据"];
                return nil;
            }];
        }];
        
        //发送控制信号
        [[_nextBtn.rac_command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
            BOOL executing = [x boolValue];
            [enableSignal sendNext:@(executing)];
        }];
        
        //监听
        [_nextBtn.rac_command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    硬性要求: 必须要有信号返回

     /*RACCommand使用注意点
         1, 必须返回一个信号
         2, executionSignals: RACCommand返回的信号时信号中的信号, 有两种方式可以获取最新的信号
         - 1,switchToLatest: 获取内部的最新信号(被动执行)
         - 2,execute:        获取内部信号(这个是主动执行)
         3, executing        用来判断是否正在执行, 第一次不准确需要跳过
         4, 一定要记得sendCompleted, 否则永远不会执行完成
         */
    
    // 一、RACCommand使用步骤:
        // 1.创建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
        // 2.在signalBlock中,创建RACSignal,并且作为signalBlock的返回值
        // 3.执行命令 - (RACSignal *)execute:(id)input
        
        // 二、RACCommand使用注意:
        // 1.signalBlock必须要返回一个信号,不能传nil.
        // 2.如果不想要传递信号,直接创建空的信号[RACSignal empty];
        // 3.RACCommand中信号如果数据传递完,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中。
        // 4.RACCommand需要被强引用,否则接收不到RACCommand中的信号,因此RACCommand中的信号是延迟发送的。
        
        // 三、RACCommand设计思想:内部signalBlock为什么要返回一个信号,这个信号有什么用。
        // 1.在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。
        // 2.当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了。
        
        // 四、如何拿到RACCommand中返回信号发出的数据。
        // 1.RACCommand有个执行信号源executionSignals,这个是signal of signals(信号的信号),意思是信号发出的数据是信号,不是普通的类型。
        // 2.订阅executionSignals就能拿到RACCommand中返回的信号,然后订阅signalBlock返回的信号,就能获取发出的值。
        
        // 五、监听当前命令是否正在执行executing
        
        // 六、使用场景,监听按钮点击,网络请求
    
    
        // 1.创建命令
        RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            
            
            NSLog(@"执行命令");
            
            // 创建空信号,必须返回信号
            //        return [RACSignal empty];
            
            // 2.创建信号,用来传递数据
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                
                [subscriber sendNext:@"请求数据"];
                
                // 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。
                [subscriber sendCompleted];
                
                return nil;
            }];
            
        }];
        
        // 强引用命令,不要被销毁,否则接收不到数据
        _conmmand = command;
        
        
       
        // 3.订阅RACCommand中的信号
        [command.executionSignals subscribeNext:^(id x) {
            
            [x subscribeNext:^(id x) {
                
                NSLog(@"%@",x);
            }];
            
        }];
        
        // RAC高级用法
        // switchToLatest:用于signal of signals,获取signal of signals发出的最新信号,也就是可以直接拿到RACCommand中的信号
        [command.executionSignals.switchToLatest subscribeNext:^(id x) {
            
            NSLog(@"%@",x);
        }];
        
        // 4.监听命令是否执行完毕,默认会来一次,可以直接跳过,skip表示跳过第一次信号。
        [[command.executing skip:1] subscribeNext:^(id x) {
            
            if ([x boolValue] == YES) {
                // 正在执行
                NSLog(@"正在执行");
                
            }else{
                // 执行完成
                NSLog(@"执行完成");
            }
            
        }];
       // 5.执行命令
        [self.conmmand execute:@1];
    
    RACMulticastConnection:(多播)用于当一个信号, 被多次订阅时, 为保证创建信号时, 避免多次调用创建信号中的block, 造成副作用, 可以使用这个类处理

    ** 封装在底层, 开发中很少使用! 就是用来解决RACSignal的副作用(副作用就是不管你订阅多少次我就只会执行一次) **
    使用

    //创建多播
     RACMulticastConnection *connection = [bookSignal publish];
     //订阅多播
      [connection.signal subscribeNext:^(id  _Nullable x) {
                NSLog(@"拿到多播数据");
            }];
     //千万不能忘记的进行连接
     [connection connect];
    
    RACScheduler: RAC中的队列, 用GCD封装的
    RACUnit: 表示stream不包含有意义的值! 可以直接理解为nil
    RACEvent: 把数据包装成信号事件

    ReactiveCocoa开发中常见用法

    • rac_signalForSelector: 替代代理
      返回一个信号, 判断是否调用某个方法
    • rac_valuesAndChangesForKeyPath: 监听某个对象的属性变化(KVO)
     //注意:keypath(<#...#>) 的使用, 可以避免在观察者里面使用字符串, @keypath(self, age) == @"age"
        [self rac_valuesForKeyPath:keypath(self, age) observer:self];
        
        //移除观察者还需要使用OC的方法
    
    • rac_signalForControlEvents: 监听某个事件
    //    监听登录按钮点击
        [[_nextBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
           //执行登录事件
            [self.loginVM.loginCommand execute:nil];
        }];
    
    • rac_addObserverForName: 监听某个通知
    //监听通知
     //不需要管理这个观察者, 不用去移除了
        [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"note" object:nil] subscribeNext:^(NSNotification * _Nullable x) {
            NSLog(@"%@", x);
        }];
        
        //发送通知
        [[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:@"Never"];
        
    
    • rac_textSignal: 监听文本变化
    • 一个界面多个请求的问题
    //RAC处理一个界面多个接口的问题, 需求: 多个接口的最后结束时间
       //Selector: 当数组所有信号都发送next后会执行选择器的方法(硬性参数: 选择器方法必须有参数, 而且参数个数和信号个数相等)
       //<#(nonnull NSArray<RACSignal *> *)#> 请求数据的信号数组
       self rac_liftSelector:@selector(@"updateUI") withSignalsFromArray:<#(nonnull NSArray<RACSignal *> *)#>
       
    

    ReactiveCocoa常见宏

    • RAC(TARGET, [KEYPATH, [NIL_VALUE]])[动态绑定, 属性对应右边的信号]
    // 只要文本框文字改变,就会修改label的文字
        RAC(self.labelView,text) = _textField.rac_textSignal;
    
    • RACObserve(self, name): 监听某个对象的某个属性, 返回的是信号
    [RACObserve(self.view, center) subscribeNext:^(id x) {
          
            NSLog(@"%@",x);
        }];
    
    • @weakify(Obj)和@strongify(Obj): 配套使用
    • RACTuplePack: 把数据包装成RACTuple(元组类)
    // 把参数中的数据包装成元组
        RACTuple *tuple = RACTuplePack(@10,@20);
    
    • RACTupleUnpack: 把RACTuple(元组类)解包成对应的数据
    // 把参数中的数据包装成元组
        RACTuple *tuple = RACTuplePack(@"xmg",@20);
        
        // 解包元组,会把元组的值,按顺序给参数里面的变量赋值
        // name = @"xmg" age = @20
        RACTupleUnpack(NSString *name,NSNumber *age) = tuple;
    

    ReactiveCocoa---映射(用于把源信号内容, 映射成新内容)

    • flattenMap---针对信号
    //flattenMap
        [[self.userName.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
            // 在这里可以处理value
            return  [RACReturnSignal return:value]; //区别: 返回的是信号
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"flattenMap --- %@", x);
        }];
    
    • Map---针对值
    //Map
    [[self.userName.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
            //在这里可以处理value
            return value; //区别: 返回的是值
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"Map --- %@", x);
        }];
    

    ReactiveCocoa---组合

    • concat---按顺序拼接信号(想按数据办事,用这个)
      需求 - 有两个数据请求, 需要把两次数据请求的数据拼接到一个数组中(还是有顺序的)
    //拼接concat
        RACSubject *subjectA = [RACSubject subject];
        RACSubject *subjectB = [RACSubject subject];
        
        //会按顺序拼接, 必须要第一个信号发送完成, 第二个信号才能获取值
        [[subjectA concat:subjectB] subscribeNext:^(id  _Nullable x) {
            NSLog(@"拼接后的值 --- %@", x);
        }];
        
        [subjectA sendNext:@"A"];
        //只有第一个信号发送完成, 才会拿到第二个信号的值
        [subjectA sendCompleted];
        [subjectB sendNext:@"B"];
    
    • then--- 用于连接两个信号, 当第一个信号完成, 才会连接then返回的信号
      订阅多次出现的副作用
    //then: 也是按顺序连接信号(都是等前面的信号完成, 再去订阅下一个信号), 和concat的区别是只能拿到最后一次信号的值
        //作用: 可以用来处理副作用(保证创建一次), 如RACSignal中的信号创建的block会调用多次的问题
        RACSignal *signaA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            NSLog(@"测试创建次数A");
            [subscriber sendNext:@"--A"];
            [subscriber sendCompleted];
            return nil;
        }];
        
        RACSignal *signaB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            NSLog(@"测试创建次数B");
            [subscriber sendNext:@"--B"];
            return nil;
        }];
        
        [[signaA concat:signaB] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
        
        [[signaA concat:signaB] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    //使用then(主要可以用来解决block嵌套不方便看的问题)

      //then: 也是按顺序连接信号(都是等前面的信号完成, 再去订阅下一个信号), 和concat的区别是只能拿到最后一次信号的值
        //作用: 可以用来处理副作用(保证创建一次), 如RACSignal中的信号创建的block会调用多次的问题
        RACSignal *signaA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            NSLog(@"测试创建次数A");
            [subscriber sendNext:@"--A"];
            [subscriber sendCompleted];
            return nil;
        }];
        
        RACSignal *signaB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            NSLog(@"测试创建次数B");
            [subscriber sendNext:@"--B"];
            return nil;
        }];
        
        //then: 拼接, 忽略掉上一个信号的值
        [[signaA then:^RACSignal * _Nonnull{
            return signaB;
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"then---%@", x);
        }] ;
        
    

    //then需求--- 第二次数据请求基于第一次数据请求的情况

    //then 解决block嵌套问题
        [self loadFirst:^(id data){
            //请求详情
            [self loadDetail:^(id data){
                // block相互嵌套, 逻辑不好看
            }];
        }];
    
    //可以看到步骤
        [[self loadFirst] then:^RACSignal *{
            return [self loadDetail];
        }] then:^RACSignal *{
            return [self loadOther];
        }];
    

    可以看到创建信号的block跑了两次

    2017-12-01 14:24:09.314948+0800 QT[3456:400220] 测试创建次数A
    2017-12-01 14:24:09.315390+0800 QT[3456:400220] --A
    2017-12-01 14:24:09.315682+0800 QT[3456:400220] 测试创建次数B
    2017-12-01 14:24:09.315925+0800 QT[3456:400220] --B
    2017-12-01 14:24:09.316393+0800 QT[3456:400220] 测试创建次数A
    2017-12-01 14:24:09.316828+0800 QT[3456:400220] --A
    2017-12-01 14:24:09.317181+0800 QT[3456:400220] 测试创建次数B
    2017-12-01 14:24:09.317479+0800 QT[3456:400220] --B
    
    • marge
    //marge: 不用前一个信号发送完成, 就可以拿到下一个信号的数据, 无顺序的
        RACSubject *subjectX = [RACSubject subject];
        RACSubject *subjectY = [RACSubject subject];
        
        [[subjectX merge:subjectY] subscribeNext:^(id  _Nullable x) {
            NSLog(@"marge --- %@", x);
        }];
        
        [subjectX sendNext:@"X数据"];
        [subjectY sendNext:@"Y数据"];
    
    • zipWith---把两个信号压缩成一个信号
    //zipWith: 不用前一个信号发送完成, 就可以拿到下一个信号的数据, 无顺序的
       RACSubject *subjectX = [RACSubject subject];
       RACSubject *subjectY = [RACSubject subject];
       
       [[subjectX zipWith:subjectY] subscribeNext:^(id  _Nullable x) {
           //x的类型是一个元组 RACTuple
           RACTupleUnpack(NSString *a, NSString *b) = x;
           NSLog(@"zipWith --- %@", x);
       }];
       
       [subjectX sendNext:@"X数据"];
       [subjectY sendNext:@"Y数据"];
    
    • combineLatest---将多个信号合并起来用的最多
    //这种用法只能处理两个信号
    //combinLatest:合并
        //reduce: 聚合
        //需求: 用多个条件判断一个事件是否执行, 如登录按钮
        RACSubject *subjectM = [RACSubject subject];
        RACSubject *subjectN = [RACSubject subject];
        
        [[subjectM combineLatestWith:subjectN] subscribeNext:^(id  _Nullable x) {
            //x - 是元组类型
            NSLog(@"%@", x);
        }];
        
        [subjectM sendNext:@"数据M"];
        [subjectN sendNext:@"数据N"];
    
    //处理多个信号的用法
        //combinLatest:合并(解决合并信号数超过2个的情况)
        //reduce: 聚合(把多个信号的值聚合成一个值)  有参数的需要自己加, 几个信号就几个参数, 参数就是值
        //需求: 用多个条件判断一个事件是否执行, 如登录按钮
        RACSubject *subjectM = [RACSubject subject];
        RACSubject *subjectN = [RACSubject subject];
        
        [[RACSignal combineLatest:@[subjectM, subjectN] reduce:^id (NSString *m, NSString *n){
            NSLog(@"m: %@ --- n: %@", m, n);
            return @"返回值给下面的x";
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"x - %@ --- 拿到的就是reduce中return的值", x);
        }];
        
        [subjectM sendNext:@"数据M"];
        [subjectN sendNext:@"数据N"];
    

    ReactiveCocoa---过滤

    • filter:--- 过滤信号, 获取满足条件的信号
      //filter: 过滤
        //需求: 如果密码的长度小于6就不处理
        [[self.pwd.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
            return value.length > 6;
        }] subscribeNext:^(NSString * _Nullable x) {
            NSLog(@"filter --- %@", x);
        }];
    
    • ignore:--- 忽略某些值的信号
    • distinctUntilChanged:--- 当值明显变化的时候就会发出信号,否则会被忽略掉(比如两次输入不一样的时候再发送, 做优化)
    • take:---从开始取N次的信号
    • takeLast:---取最后N次的信号
    • takeUntil:---获取某个信号直到某个信号执行完成(到文本框销毁)
    • skip:---跳过几个信号
    • switchToLatest:---获取最新的信号

    ReactiveCocoa---秩序

    • doNext:---执行Next之前, 会先执行这个block
    • doCompleted:---执行sendCompleted之前, 会先执行这个Block

    ReactiveCocoa---线程

    • deliverOn: 内容传递到指定线程中, 副作用在原来的线程中(把多次创建信号时block中的代码称之为副作用)
    • subscribeOn: 内容和副作用都会传递到指定线程中

    ReactiveCocoa---时间

    • timeout:---超时,让一个信号在一定的事件后, 自动报错
    • interval:---定时,每隔一段时间发出信号
      //定时器
        //interval: 隔多少秒发送
        //RACScheduler: 线程类
        [[RACSignal interval:3 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
            NSLog(@"执行了定时器%@", x);
        }];
    
    • delay:--- 延迟, 延迟发送next
    //delay
        //延迟发送数据
        [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@"要延迟发送的数据"];
            return nil;
        }] delay:2] subscribeNext:^(id  _Nullable x) {
            NSLog(@"拿到延迟发送的数据 --- %@", x);
        }];
    

    ReactiveCocoa---重复

    • retry:---重试, 只要失败就会重新执行创建信号中的block,直到成功
    • throttle:---节流 当某个信号发送比较频繁时, 可以使用节流, 在某一段时间不发送信号内容, 过一段时间获取信号的最新内容发出

    注意点

    • RACSignal和RACSubject一定要先订阅再发送数据
    • 数据请求是最好是使用RACReplaySubject, 避免发送数据在订阅之前(RACCommand底层用的就RACReplaySubject)
    • RACSubject更能避免RACSignal的副作用

    相关文章

      网友评论

          本文标题:iOS ReacttiveObjc

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