RactiveObjc框架源码阅读

2021-01-06  本文已影响0人  Sweet丶

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循环引用

上一篇下一篇

猜你喜欢

热点阅读