美文网首页iOS记录
iOS RAC学习之路(二)

iOS RAC学习之路(二)

作者: 大大盆子 | 来源:发表于2017-07-04 17:21 被阅读1251次

    前言

    之前对RAC有了一个基本的认识,了解了它的作用,以及RAC的运行机制,我们知道只要是信号(RACSignal),我们就能对它进行一顿订阅,然后执行触发操作;接下来我们来学习一下RAC中常用的类以及一系列的用法。


    RACSignal

    这是一个信号类,表示一个信号源,只要有数据改变就会把数据包装成信号传递出去,它本身不具备发送信号的能力,而是交给内部的一个订阅者(RACSubscriber)去发出,然后当信号被订阅之后,就会在其内部就创建一个订阅者,所以在信号内部就可以发送信号了,之前也对RACSignal做了一个简单的了解,下面学习一下更多的用法

    • 常用事件处理
    • Target-Action
     [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
            //x==btn
            NSLog(@"%@",x);
            [self push];
     }];
    
    • Delegate
    //因为订阅信号是void返回类型的,所以只能代替void返回类型的delegate
    [textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
            //x==textField.text
            NSLog(@"%@",x);
    }];
    
    • KVO
    //直接用宏
    [RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
            //x==新背景颜色
            NSLog(@"%@",x);
     }];
    //也可以这样
    __weak typeof(self) weakSelf = self;
     [[self.view rac_valuesForKeyPath:@"backgroundColor" observer:weakSelf] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
     }];
    
    • 通知
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
            //x==userInfo
            NSLog(@"%@",x);
     }];
    
    • 常用方法
    • flattenMapmap
      这是两个映射方法,将源信号内容映射成新的内容,就像signal管道上的中间处理器,从这里走过的signal都会经过一段处理后,变成新的signal继续传输。
    //map,将输出NSNumber的signal转换成输出NSString
    RACSignal *mapSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
    
            [subscriber sendNext:@(1)];
            return nil;
        }] map:^id _Nullable(id  _Nullable value) {
    
            return [NSString stringWithFormat:@"%@",value];
        }];
        [mapSignal subscribeNext:^(id  _Nullable x) {
            //NSString类型
            NSLog(@"x");
        }];
    
    //flattenMap,将输出NSNumber的signal转换成输出NSString
    RACSignal *mapSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            return nil;
            
        }] flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
            
            return [RACReturnSignal return:[NSString stringWithFormat:@"%@",value]];
        }];
        [mapSignal subscribeNext:^(id  _Nullable x) {
            //NSString类型
            NSLog(@"x");
        }];
    

    两者之间的区别就在于,map中Block返回转换对象,flattenMap返回转换对象的信号。一般信号发出的值不是信号,使用map;如果是信号则使用flattenMap,它可以处理信号中的信号。

    • merge:把多个信号合并成一个信号,只需订阅这一个信号就相当于订阅了多个信号,任何一个信号有新值的时候都会触发调用。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            return nil;
        }];
        RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(2)];
            return nil;
        }];
        RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(3)];
            return nil;
        }];
        RACSignal *mergeSignal = [RACSignal merge:@[signal1,signal2,signal3]];
        [mergeSignal subscribeNext:^(id  _Nullable x) {
            //分别输出1,2,3
            NSLog(@"%@",x);
        }];
    
    • concat:将多个信号有顺序的连接起来,按照顺序接收信号,但是一定要之前的信号完成了才能发送下一个信号。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            //发送信号完成,表示不再订阅了,内部会自动调用[RACDisposable disposable]取消订阅信号。
            [subscriber sendCompleted];
            return nil;
        }];
        RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(2)];
            [subscriber sendCompleted];
            return nil;
        }];
        RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(3)];
            [subscriber sendCompleted];
            return nil;
        }];
        RACSignal *concatSignal = [RACSignal concat:@[signal2,signal1,signal3]];
        [concatSignal subscribeNext:^(id  _Nullable x) {
            //分别输出2,1,3
            NSLog(@"%@",x);
        }];
    
    • then:用于连接两个信号,内部也是使用concat,当前一个信号完成之后才会连接then返回的信号,但是会忽略前一个信号,只会触发下个信号。
        RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            [subscriber sendCompleted];
            return nil;
        }];
       RACSignal *thenSignal =  [signal1 then:^RACSignal * _Nonnull{
          return  [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
               [subscriber sendNext:@(2)];
               [subscriber sendCompleted];
               return nil;
           }];
       }];
        [thenSignal subscribeNext:^(id  _Nullable x) {
            //输出2
            NSLog(@"%@",x);
        }];
    
    • zip:将对各信号压缩成一个信号,只有当几个信号同时sendNext的时候才会触发压缩流的next事件,其中每一个信号send的内容都是一一对应的。
        RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            //不会覆盖上一个信号
            [subscriber sendNext:@(3)];
            return nil;
        }];
        RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            
            [subscriber sendNext:@(2)];
            return nil;
        }] ;
        RACSignal *zipSignal = [RACSignal zip:@[signal1,signal2]];
        [zipSignal subscribeNext:^(id  _Nullable x) {
            //输出(1,2)
            NSLog(@"%@",x);
        }];
    
    • combineLatest:将多个信号组合起来,当其中每一个信号都sendNext之后,才会触发组合的信号,其中每一个信号再次sendNext都会覆盖之前的信号内容,返回的是一个RACTuple(元组,类似于NSArray)。
        RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            //将覆盖之前的信号,这就是跟zip的区别
            [subscriber sendNext:@(3)];
            return nil;
        }];
        RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(2)];
            return nil;
        }];
       //如果其中一个信号不sendNext,则不会触发组合信号
        RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] ];
        [combineSignal subscribeNext:^(id  _Nullable x) {
            //输出(3,2)
            NSLog(@"%@",x);
        }];
    
    • rac_liftSelector: withSignalsFromArray::当信号组中每一个信号都至少一次sendNext之后,将触发Selector方法,类似于combineLatest
        RACSubject *subject1 = [RACSubject subject];
        RACSubject *subject2 = [RACSubject subject];
        [[self rac_liftSelector:@selector(updateWithParameter1:parameter2:) withSignals:subject1,subject2, nil] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        [subject1 sendNext:@1];
        [subject2 sendNext:@2];
    
    • reduceEach:一般用于元组,把元组的值聚合成一个值。
    RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] ];
        RACSignal *reduceSignal = [combineSignal reduceEach:^id (NSNumber *num1,NSNumber *num2){
            return @(num1.doubleValue+num2.doubleValue);
        }];
        [reduceSignal subscribeNext:^(id  _Nullable x) {
            //输出3
            NSLog(@"%@",x);
        }];
    //等同于+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock
    //    RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] reduce:^id (NSNumber *num1,NSNumber *num2){
    //        return @(num1.doubleValue+num2.doubleValue);
    //    }];
    
    • filter:过滤信号,添加筛选条件,只有符合的才会触发调用。
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            [subscriber sendNext:@"3"];
            return nil;
        }];
        RACSignal *filterSignal = [signal1 filter:^BOOL(id  _Nullable value) {
            return [value isKindOfClass:[NSNumber class]];
        }];
        [filterSignal subscribeNext:^(id  _Nullable x) {
            //输出1
            NSLog(@"%@",x);
        }];
        
        //数组的筛选
        RACSequence *sequence = [@[@(1),@(2),@"3"].rac_sequence filter:^BOOL(id  _Nullable value) {
            return [value isKindOfClass:[NSNumber class]];
        }];
        [sequence.signal subscribeNext:^(id  _Nullable x) {
            //输出1,2
            NSLog(@"%@",x);
        }];
    
    • distinctUntilChanged:当前值跟上一次的值不同的时候,就会触发调用,否则被忽略。
    [textField.rac_textSignal.distinctUntilChanged subscribeNext:^(NSString * _Nullable x) {
            //变化时输出变化之后的值
            NSLog(@"%@",x);
        }];
    
    • take:从第一个信号开始设置信号发送的有效的个数。
        RACSignal *signal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            [subscriber sendNext:@(2)];
            return nil;
        }] take:1];
        
        [signal subscribeNext:^(id  _Nullable x) {
            //输出1,因为take为1,所以有效的只有最开始的那一个,其他的忽略掉了
            NSLog(@"%@",x);
        }];
    
    • takeLast:从最后一个开始设置信号发送的有效个数,必须sendCompleted,不然不知道总共多少个信号。
        [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            [subscriber sendNext:@(2)];
            [subscriber sendCompleted];
            return nil;
        }] takeLast:1] subscribeNext:^(id  _Nullable x) {
            //输出2
            NSLog(@"%@",x);
        }];
    
    • takeUntil[signal1 takeUntil:signal2],当signal2已经sendNext或者sendCompleted,signal1就会失效。
        RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            return nil;
        }];
        RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(2)];
            return nil;
        }];
        [[signal1 takeUntil:signal2] subscribeNext:^(id  _Nullable x) {
            //什么都不会输出,因为signal2已经sendNext,所以signal1就会失效
            NSLog(@"%@",x);
        }];
    
    • skip:跳跃,从第一个发出的信号开始跳。
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            [subscriber sendNext:@(2)];
            [subscriber sendNext:@(3)];
            return nil;
        }] skip:2] subscribeNext:^(id  _Nullable x) {
            //输出3
            NSLog(@"%@",x);
        }];
    
    • doNext:在执行sendNext之前会执行这个。
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            return nil;
        }] doNext:^(id  _Nullable x) {
            x = [NSString stringWithFormat:@"%@haha",x];
            //输出1haha,在订阅回调之前执行
            NSLog(@"%@",x);
        }] subscribeNext:^(id  _Nullable x) {
            //输出1
            NSLog(@"%@",x);
        }];
    
    • timeout:在超过设定时间范围之后让信号报错,且不能发送内容。
        RACSubject *subject = [RACSubject subject];
        [[subject timeout:3 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id  _Nullable x) {
            //只输出1
            NSLog(@"%@",x);
        } error:^(NSError * _Nullable error) {
            //3秒之后输出错误日志
            NSLog(@"%@",error);
        }];
        [subject sendNext:@1];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [subject sendNext:@2];
        });
    
    • interval:定时,每隔一定时间发出时间信号。
    //RACScheduler:队列
    [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
            //每隔一秒输出当前时间
            NSLog(@"%@",x);
    }];
    
    • delay:延时发送信号
        [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@(1)];
            return nil;
        }] delay:3] subscribeNext:^(id  _Nullable x) {
            //3秒之后输出1
            NSLog(@"%@",x);
        }];
    
    • retry:重试,只要失败,就会重新执行创建信号中的block,直到成功。
        __block NSInteger i = 0;
        [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            i++;
            if (i > 10) {
                [subscriber sendNext:@(1)];
            }else{
                [subscriber sendError:nil];
            }
            return nil;
        }] retry] subscribeNext:^(id  _Nullable x) {
            //重试10次之后输出1
            NSLog(@"%@",x);
        }error:^(NSError * _Nullable error) {
            NSLog(@"%@",error);
        }];
    
    • throttle:节流,当某个信号发送比较频繁的时候,可以限制在一定之间内不接受信号,等过了这个时间再取最后发送的信号内容发出,类似于bufferWithTime:onScheduler:
        RACSubject *subject = [RACSubject subject];
    // [subject bufferWithTime:1 onScheduler:[RACScheduler currentScheduler]];
        [[subject throttle:1] subscribeNext:^(id  _Nullable x) {
            //输出3,拿到最后发出的内容3
            NSLog(@"%@",x);
        }];
        [subject sendNext:@1];
        [subject sendNext:@2];
        [subject sendNext:@3];
    
    • deliverOn:内容传递切换到指定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。
    • subscribeOn:内容传递和副作用都会切换到指定线程中。

    RACSubject

    信号提供者,本身可以充当信号,又能发送信号,继承自RACSignal,但是底层实现跟RACSignal有些不一样,当订阅信号的时候会创建订阅者并保存订阅响应Block,而发送信号的时候会遍历订阅者,然后分别调用nextBlock。它提供的API很少,但是经常使用,因为它继承自RACSignal。这里顺便来看一下方法 flattenswitchToLatest,这两个都只能用来处理信号中的信号。

    • flatten:压平信号中的信号,信号中的信号我们称之为子信号,flatten可以拿到所有子信号发送的值。
    RACSubject *subject = [RACSubject subject];
    RACSubject *subSubject1 = [RACSubject subject];
    RACSubject *subSubject2 = [RACSubject subject];
    [subject subscribeNext:^(id  _Nullable x) {
        //分别输出subSubject1,subSubject2,但是不能拿到其中的值
        NSLog(@"%@",x);
    }];
    [subject.flatten subscribeNext:^(id  _Nullable x) {
        //分别输出1,2, flatten可以拿到所有子信号发送的值
        NSLog(@"%@",x);
    }];
    [subject sendNext:subSubject1];
    [subject sendNext:subSubject2];
    [subSubject1 sendNext:@1];
    [subSubject2 sendNext:@2];
    
    • switchToLatest:与flatten相同,压平信号中的信号,不同的是,在存在多个子信号时候只会拿到最新的子信号,然后输出最新的子信号的值。
    RACSubject *subject = [RACSubject subject];
    RACSubject *subSubject1 = [RACSubject subject];
    RACSubject *subSubject2 = [RACSubject subject];
    [subject subscribeNext:^(id  _Nullable x) {
        //分别输出subSubject1,subSubject2,但是不能拿到其中的值
        NSLog(@"%@",x);
    }];
    [subject.switchToLatest subscribeNext:^(id  _Nullable x) {
        //输出2, switchToLatest只会拿到最新的子信号发送的值
        NSLog(@"%@",x);
    }];
    [subject sendNext:subSubject1];
    [subject sendNext:subSubject2];
    [subSubject1 sendNext:@1];
    [subSubject2 sendNext:@2];
    

    RACReplaySubject

    重复提供信号类,继承自RACSubject,它可以先发送信号,再订阅信号,原理就是将发送的信号内容保存了起来,当订阅信号的时候再将之前保存的信号,由订阅者一个一个的发送出来,而保存信号的容量由capacity来控制。

     RACReplaySubject *replaySubject = [RACReplaySubject replaySubjectWithCapacity:5];
     [replaySubject subscribeNext:^(id  _Nullable x) {
         //输出1
         NSLog(@"%@",x);
     }];
     [replaySubject sendNext:@1];
     [replaySubject subscribeNext:^(id  _Nullable x) {
         //输出1
         NSLog(@"%@",x);
     }];
    

    RACMulticastConnection

    这是一个组播连接类,是对信号的一个封装处理,当一个信号被多次订阅时,则会多次执行didSubscribe这个Block,造成副作用,而这个类就能避免多次执行didSubscribe,是一对多的单向数据流,一般用来处理信号被多次订阅的情况。

    __block int i = 0;
    //创建信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(i)];
        i ++;
        return nil;
    }];
    //创建RACMulticastConnection对象
    RACMulticastConnection *connect = [signal publish]
     [connect.signal subscribeNext:^(id  _Nullable x) {
        //输出0
        NSLog(@"%@",x);
    }];
    [connect.signal subscribeNext:^(id  _Nullable x) {
        //输出0,当再次订阅时,不会再执行didSubscribe,所以并没有i++
        NSLog(@"%@",x);
    }];
    //连接
    [connect connect];
    
    • 方法解析及实现原理
    • publishmulticast:这是对RACMulticastConnection初始化方法的一个封装,publish其实就是调用了multicast,并把创建好的RACSubject对象传给它,而multicast也就是调用了RACMulticastConnection的初始化方法,将原始信号传给source,把RACSubject对象传给subject
    • 当我们订阅connect.signal,其实就是订阅subject,然后将subject的订阅者保存起来,而调用[connect connect]的时候,会订阅原始信号(source),而source的订阅者就是subject,这时候subject就会执行[subject sendNext],之后就会遍历subject所有的订阅者,逐一发送信号,触发外部subscribeNext回调。

    RACCommand

    这是一个命令类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,一般来说是在UI上的某些动作来触发这些事件,比如点击一个按钮,RACCommand的实例能够决定是否可以被执行,一般用于网络请求,监控请求过程。

    • 公开的属性及方法
    @interface RACCommand: NSObject
    
    //这是一个二阶信号,表示信号中包含子信号,一般使用flatten或switchToLatest来降阶
    @property (nonatomic, strong, readonly) RACSignal<RACSignal<ValueType> *> *executionSignals;
    
    //这个信号表示当前RACCommand是否正在执行,YES/NO
    @property (nonatomic, strong, readonly) RACSignal<NSNumber *> *executing;
    
    //这个信号表示RACCommand是否可用,如果初始化传NO或者allowsConcurrentExecution=NO,那个这个信号返回NO,否则为YES
    @property (nonatomic, strong, readonly) RACSignal<NSNumber *> *enabled;
    
    //表示RACCommand执行过程中产生的错误信号,当对错误信号进行处理的时候应该subscribeNext去订阅,而不是subscribeError。
    @property (nonatomic, strong, readonly) RACSignal<NSError *> *errors;
    
    //是否允许并发执行,默认为NO
    @property (atomic, assign) BOOL allowsConcurrentExecution;
    
    /**
     初始化
     @param signalBlock 返回信号的Block,在其内部进行保存,当进行execute的时候才会调用该Block
     @return self
     */
    - (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;
    
    /**
     初始化
     @param enabledSignal 是否可用
     @param signalBlock 返回信号的Block,在其内部进行保存,当进行execute的时候才会调用该Block
     @return self
     */
    - (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;
    
    /**
     执行
     @param input 输出内容
     @return 组播连接对象的signal
     */
    - (RACSignal<ValueType> *)execute:(nullable InputType)input;
    
    @end
    
    • 使用步骤:
    1. 创建命令,初始化RACCommand对象,内部做的事情:
    • 将传入的signalBlock进行保存
    • 初始化自己的4个信号,executionSignalsexecutingenablederrors
    1. signalBlock中创建RACSignal,用来做数据传递,如果不需要可以创建空信号[RACSignal empty]
    2. 执行命令execute,内部做的事情:
    • 调用之前保存的signalBlock,并将execute参数带入进去,拿到signalBlock返回的信号。
    • 再将该信号内容切换到主线程,然后multicastRACMulticastConnection对象,避免多次订阅导致重复创建信号。
    • 将connection.signal mapexecutionSignals,当原始信号发送数据的时候,通过switchToLatestflatten来降阶取值。
      //1.创建命令对象
      RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
          //输出1,由execute传入
          NSLog(@"%@",input);
          //2.创建信号
          return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
              [subscriber sendNext:@(2)];
              // 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。
              [subscriber sendCompleted];
              return nil;
          }];
      }];
    
      //获取信号传输的数据
      [command.executionSignals.switchToLatest subscribeNext:^(id x) {
          //输出2
          NSLog(@"%@",x);
      }];
      //这里用flatten跟switchToLatest也是一样的
      [[command.executionSignals flatten] subscribeNext:^(id  _Nullable x) {
          //输出2
          NSLog(@"%@",x);
      }];
    
      //监听命令是否执行完毕,初始化时会调用一次,用skip直接跳过。
      [[command.executing skip:1] subscribeNext:^(id x) {
          if ([x boolValue] == YES) {
              // 正在执行
              NSLog(@"正在执行");
          }else{
              // 执行完成
              NSLog(@"执行完成");
          }
      }];
    
      //3.执行命令
      RACSignal *connectSignal = [command execute:@1] ;
      [connectSignal subscribeNext:^(id  _Nullable x) {
          //输出2,connectSignal是connect.signal
          NSLog(@"%@",x);
      }];
    

    RACChannel

    这是一个通道类,可以理解为一个双向的连接,连接的两端都配有RACChannelTerminal(通道终端,继承自RACSignal,且又实现了RACSubscriber协议,所以它可以充当信号,又能发送信号),分别是leadingTerminalfollowingTerminal,只要其中任何一端输出信号,另一端都会有相同的信号输出。我们平时很少直接使用RACChannel,而是使用RACChannelTo

    • RACChannelTo:使用这个宏要传入相关对象以及它的属性,比如RACChannelTo(view,backgroundColor),实际上创建了一个RACKVOChannel对象,在内部将其一端的leadingTerminal与view的backgroundColor属性进行绑定,并将其另一端followingTerminal暴露出来,也就是RACChannelTo的返回值,我们可以对followingTerminal进行订阅,拿到view. backgroundColor,同样followingTerminal发送信号也会同步到view.backgroundColor。

    • 用它来实现双向绑定,RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);将button跟view的背景颜色进行绑定,两边相互影响,进行同步。

        RACChannelTerminal *followT = RACChannelTo(view,backgroundColor);
        [followT subscribeNext:^(id  _Nullable x) {
            //每点击一次就输出一次随机颜色
            NSLog(@"%@",x);
        }];
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
        [tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
            //改变view.backgroundColor
            [followT sendNext:RandomColor];
        }];
    
        //将_textField.backgroundColor跟view.backgroundColor绑定
        RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);
    

    常用宏

    • RAC(TARGET, ...):给某个对象的某个属性进行绑定。
      //当textfield开始编辑时,关闭button响应
     RAC(_button,enabled) = [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] mapReplace:@NO];
    
    • RACObserve(TARGET, KEYPATH):KVO,监听某个对象的属性,返回的是信号。
    [RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
        //x==新背景颜色
        NSLog(@"%@",x);
    }];
    
    • RACChannelTo:用于双向绑定的一个通道终端。
    //将_textField.backgroundColor跟view.backgroundColor绑定
      RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);
    
    • RACTuplePack:将数据包装成RACTuple(元组)。
    RACTuple *tuple = RACTuplePack(@1,@2,@"3");
    
    • RACTupleUnpack(...):把元组解包成对应的数据
     //传入需要解析生成的变量名,从第一个开始解析
     RACTupleUnpack(NSNumber *num1,NSNumber *num2) = tuple;
     //输出1,2
     NSLog(@"%@,%@",num1,num2);
    

    相关文章

      网友评论

        本文标题:iOS RAC学习之路(二)

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