美文网首页
RACSubject、RACReplaySubject(内附冷信

RACSubject、RACReplaySubject(内附冷信

作者: 下班不写程序 | 来源:发表于2020-10-10 11:38 被阅读0次

    文章系列
    《ReactiveCocoa 概述》
    《RACSignal》
    《RACDisposable》
    《RACSubject、RACReplaySubject(内附冷信号和热信号的区别)》
    《集合RACTuple、RACSequence》
    《RAC 中的通知、代理、KVO, 基本事件、方法的监听》
    《rac_liftSelector》
    《RACMulticastConnection》
    《RACCommand》
    《RAC - 核心方法bind》
    《RAC - 定时器》
    《RACScheduler》
    《RAC - 点击获取验证码 demo》
    《RAC - 映射(Map & flattenMap)》
    《RAC信号操作解释合集》
    《RAC - 信号的生命周期》

    • RACSubject

    RACSignal 是冷信号, 不能够自己发送信号, 需要订阅者订阅, 特点是确定未来, 也就是知道什么时候结束/终止, 无视订阅者, 不管谁订阅, 都是从头开始执行一段老代码

    帮助理解: 冷信号 相当于 剧本, 当订阅者订阅时, 就相当于开始拍戏, 不管谁订阅, 都是从头开始拍, 拍完了也就结束了.

    RACSubject 继承自RACSignal, 是热信号, 也就是说既可以充当信号,也可以发送信号, 并不确定什么时候终止, 关心订阅者, 先来先得、后来少得

    帮助理解: 热信号 相当于 拍好的戏, 当订阅者订阅时, 就开始演戏, 接下来再有订阅者订阅, 演到哪里就继续演, 不会重新从头开始, 即先来的看得多、后来看的就少.

    代码分析:

        // 1.创建信号
        RACSubject *subject = [RACSubject subject];
        
        // 2.订阅信号
        [subject subscribeNext:^(id  _Nullable x) {
            NSLog(@"x = %@", x);
        }];
        
        // 3.发送数据
        [subject sendNext:@10];
    

    ↓[RACSubject subject] 内部实现↓

    + (instancetype)subject {
        return [[self alloc] init];
    }
    
    - (instancetype)init {
        self = [super init];
        if (self == nil) return nil;
    
        // 创建一个 复合的_disposable 对象, 用于取消订阅
        _disposable = [RACCompoundDisposable compoundDisposable];
        // 创建一个 _subscribers 订阅者集合, 用来保存订阅者
        _subscribers = [[NSMutableArray alloc] initWithCapacity:1];
        
        return self;
    }
    

    ↓ 订阅信号 subscribeNext: 内部实现↓
    其实内部也RACSignal 信号订阅大致相同, 唯一不同的是subscribe: 方法的实现:

    - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
        NSCParameterAssert(subscriber != nil);
    
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    
        NSMutableArray *subscribers = self.subscribers;
        @synchronized (subscribers) {
            // 注意: 每次订阅, 都将订阅者添加至 信号内部的_subscribers 数组中
            [subscribers addObject:subscriber];
        }
        
        [disposable addDisposable:[RACDisposable disposableWithBlock:^{
            @synchronized (subscribers) {
                // Since newer subscribers are generally shorter-lived, search
                // starting from the end of the list.
                NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
                    return obj == subscriber;
                }];
    
                if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
            }
        }]];
    
        return disposable;
    }
    

    ↓ 发布消息sendNext: 内部实现↓

    - (void)sendNext:(id)value {
        // 遍历_subscribers 集合, 向每一个订阅者发送sendNext: 消息, 即所有订阅者依次发送消息
        [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
            [subscriber sendNext:value];
        }];
    }
    
    总结
    1. 创建的subject的是内部会创建一个数组_subscribers用来保存所有的订阅者
    2. 订阅信息的时候会创建订阅者,并且保存到数组中
    3. 遍历subject中_subscribers中的订阅者,依次发送信息

    注意

    RACSubject 可以被订阅多次,并且只能是先订阅后发布, 因为:先发送, 再有订阅者, 订阅者收不到订阅之前的消息, 所以称之为先来先得, 晚来少得
    • RACReplaySubject
      针对RACSubject 的注意点, 偏偏要先发送消息, 再去订阅信号, 该怎么办呢???

    这里就可以使用RACReplaySubject , 它继承自RACSubject, 目的就是来解决先发送信号后订阅的问题.

    代码分析: 和RACSubject 的使用一毛一样

        // 先发送信号
        [replaySubject sendNext:@10];
        
        // 后订阅信号
        [replaySubject subscribeNext:^(id  _Nullable x) {
            // 可以正常打印
            NSLog(@"x = %@", x);
        }];
    

    ↓具体实现原理↓

    1. RACReplaySubject 对象创建的时候, 会在父类的基础之上多做一步,创建一个数组用来保存发送的数据(当_subscribers 中所有订阅者都成功发送了数据, 那么就会删除当前要发送的数据, 避免出现一个数据重复发送的问题)
    2. 发送数据: 当有订阅者订阅时,发送数据; 没有订阅者订阅时发送失败, 就不发送,等待新的订阅者.
    3. 订阅信号, 先遍历一次保存数据的数组, 如果有就执行第二步

    .End

    相关文章

      网友评论

          本文标题:RACSubject、RACReplaySubject(内附冷信

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