美文网首页
RactiveObjc框架源码阅读

RactiveObjc框架源码阅读

作者: Sweet丶 | 来源:发表于2021-01-06 17:01 被阅读0次

    RactiveObjc是一套OC语言的实现响应式编程的一套框架, 我们通过这一套框架,我们项目中如果使用MVVM架构,用这个框架更方便得实现VM与V/C之间的绑定。

    // 假设VM里面是使用RACSignal *OM021Signal,C控制器中通过subscribeNext:订阅VM的OM021Signal来接收回调消息
    // VM中的信号
    - (RACSignal *)OM021Signal {
        if (!_OM021Signal) {
            @weakify(self);
            _OM021Signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                @strongify(self);
                NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
                [[YSTNetworkingManager new] sendHttp:OM021 content:infoDict controller:self.vc animate:NO completion:^(NSString *msgCode, NSString *isMore, NSDictionary *backCodeDict, NSDictionary *backContentDict, NSArray *backContentListDict, NSDictionary *backHeadDict) {
                    @strongify(self);
                    NSNumber *nomoreDataStatu = [busiState isEqualToString:@"00"] ? @(0) : @(1);
                    [subscriber sendNext:nomoreDataStatu];
                    [subscriber sendCompleted];
                } error:^(NSError *connectionError) {
                    [subscriber sendNext:@(2)];
                    [subscriber sendCompleted];
                }];
                return [RACDisposable disposableWithBlock:^{ }];
            }];
        }
        return _OM021Signal;
    }
    

    一、RACSignal的实现原理

    1. 创建信号RACSignal

    首先调用[RACDynamicSignal createSignal:didSubscribe];创建RACDynamicSignal记录(设置属性值)didSubscribe(是一个返回RACDisposable * 的block)。

    + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
        RACDynamicSignal *signal = [[self alloc] init];
        signal->_didSubscribe = [didSubscribe copy];
        return [signal setNameWithFormat:@"+createSignal:"];
    }
    
    // 比如实际使用时控制器中订阅信号的sendNext:
    @weakify(self);
    [self.om021ViewModel.OM021Signal subscribeNext:^(NSNumber *nomoreDataStatu) {
        @strongify(self);
        if ([nomoreDataStatu integerValue] == 0) {
            [self.mainView reloadWithOM021Model:self.om021ViewModel];
        }
    }];
    
    2. 信号的订阅

    对信号我们可以有3种订阅:

    - (RACDisposable *)subscribeNext:(void (^)(ValueType _Nullable x))nextBlock;
    - (RACDisposable *)subscribeError:(void (^)(NSError * _Nullable error))errorBlock;
    - (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock;
    
    2.1 由于3种订阅的原理都是相通的,所以我们分析其中一种就可以了。我们对上面信号subscribeNext:订阅时, nextBlock最终收到回调的过程是这样的:
    1. 创建RACSubscriber,引用nextBlock.
    2. 创建RACPassthroughSubscriber,引用上一步中的RACSubscriber、self(即RACDynamicSignal)、disposable(创建了RACCompoundDisposable,负责清除订阅信息的)
    3. 调用didSubscribe(subscriber)(在创建RACSignal时记录的那个block),外部使用时在didSubscribe中可以拿到订阅者subscriber
    4. 使用[subscriber sendNext:@1]; 之后,会拿到对应的nextBlock调用。
    5. subscribeNext:的nextBlock收到回调。
    // 1. 创建RACSubscriber,引用nextBlock
    - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
        RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
        return [self subscribe:o]; // self == RACDynamicSignal
    }
    // 2.创建RACPassthroughSubscriber,
    // 引用上一步中的RACSubscriber、self(即RACDynamicSignal)、disposable.
    // 最后执行订阅的self.didSubscribe(subscriber)
    - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    
        if (self.didSubscribe != NULL) {
            RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
                RACDisposable *innerDisposable = self.didSubscribe(subscriber);
                [disposable addDisposable:innerDisposable];
            }];
    
            [disposable addDisposable:schedulingDisposable];
        }
        
        return disposable;
    }
    
    2.2 订阅者subscriber可以发送3种信号
    // 可以自己根据实际情况去发送对应的信号
    // subscriber调用的sendNext方法实现:
    - (void)sendNext:(id)value {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;
        nextBlock(value);
    }
    - (void)sendError:(NSError *)e {
        void (^errorBlock)(NSError *) = [self.error copy];
        [self.disposable dispose];
        if (errorBlock == nil) return;
        errorBlock(e);
    }
    - (void)sendCompleted {
        void (^completedBlock)(void) = [self.completed copy];
        [self.disposable dispose];
        if (completedBlock == nil) return;
        completedBlock();
    }
    
    3. 信号订阅的销毁
    信号有订阅时会产生的各个对象之间的引用.png

    我们关心订阅时要收到回调也当然要关心如何解除订阅,订阅相关的nextBlock等的销毁会随着订阅者subscriber的销毁发生. 我们一般会让ViewModel持有信号的,信号销毁跟随ViewModel的。

    在信号收到订阅时,通过源码可知,subscriber引用了RACCompoundDisposable,这个对象会引用相关的RACDisposable。首先订阅者subscriber是一个临时的对象,在超出作用域后就会销毁。
    subscriber在销毁时,它的属性:RACDisposable、订阅信号的nextBlock、completedBlock、errorBlock也跟着销毁。

    - (void)dealloc {
    // 我们创建信号的时候可以将需要随着订阅结束而移除的对象放在dispose当中
    // 创建信号时候的返回值return [RACDisposable disposableWithBlock:^{ // 需销毁的代码}];
        [self.disposable dispose];
    }
    

    如果是subscriber有被强引用了的话,比如如下情况,可以手动调用:

    /** 在RACDisposable中有self.subscriber = nil;来完成订阅者及时的释放。
    下面3种方式都可以触发:
    1. [subscriber sendCompleted];
    2. [subscriber sendError:error];
    3. 创建信号时在didSubscribe返回的RACDisposable对象, 手动调用disposable方法。
    */
    @weakify(self);
    _scoreRankSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        @strongify(self);
    
        self.subscriber = subscriber;
        return [RACDisposable disposableWithBlock:^{
            @strongify(self);
            self.subscriber = nil;// 不需要用了进行清理
        }];
    }];
    
    二、RACSubject的使用

    RACSubject是继承于RACSignal的一个信号,相比其父类RACSignal,它增加的功能是实现了<RACSubscriber>协议,自己即是信号也是订阅者,可以发信号给自己的订阅者们。

    它内部用数组记录了所有订阅者,在每次外部订阅自己时,也是像RACSignal的订阅一样,创建RACPassthroughSubscriber, 然后添加在自己的subscribers数组中.
    发送信号时调用- (void)sendNext:(id)value, 遍历数组逐个调用[subscriber sendNext:value];。

    - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    
        NSMutableArray *subscribers = self.subscribers;
        @synchronized (subscribers) {
            [subscribers addObject:subscriber];
        }
        // 这个disposable中的block是在订阅结束之后会调用,起到的作用是从数组中移除一个订阅者
    // 订阅结束的方式:sendCompleted、sendError、调用dispose方法
        [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;
    }
    // RACSubject对象可以主动调用sendNext:方法,
    // 内部实现是遍历自己的订阅者数组subscribers, 逐个调用[subscriber sendNext:value];
    - (void)sendNext:(id)value {
        [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
            [subscriber sendNext:value];
        }];
    }
    

    什么时候销毁呢?
    在使用时我们首先是创建一个RACSubject对象,然后可以对这个进行订阅会将订阅者加入数组中,当RACSubject对象销毁后,数组中每个订阅者也会销毁

    三、RACReplaySubject

    继承于RACSubject的类,在父类的基础上增加了对发送过的数据保存到数组的功能,在有订阅时,会先把之前保存的数据先sendNext一遍。

    四、RAC的一些使用注意

    RAC的源码追踪,可以发现,如果在block中引用了self,需要使用@weakify(self),否则会导致内存泄漏。
    正确使用@weakify 和@strongify防止block循环引用

    相关文章

      网友评论

          本文标题:RactiveObjc框架源码阅读

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