本文基于ReactiveObjC 3.1.0版本进行解析。共分两部分:一是核心流程。二是分析实践。
一、核心流程
创建信号
先来看看创建信号的过程吧:
// 创建信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { [subscriber sendNext:@"1"]; [subscriber sendNext:@"2"]; [subscriber sendNext:@"3"]; [subscriber sendCompleted]; return [RACDisposable disposableWithBlock:^{}]; }]; // 订阅信号 [signal subscribeNext:^(id _Nullable x) { NSLog(@"next: %@", x); } error:^(NSError * _Nullable error) { NSLog(@"error: %@", error); } completed:^{ NSLog(@"completed"); }]; |
这一段代码,相信对于使用过ReactiveCocoa的同学,都不陌生。就是创建了一个信号,这个信号发射了1、2、3以及一个completed。接着看看createSignal的过程。
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe { return [RACDynamicSignal createSignal:didSubscribe]; } |
RACSignal内部创建信号的时候,实际上调用的是RACDynamicSignal创建信号的过程。同时我们也可以看到,传递的参数是外面的这个block:
^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { [subscriber sendNext:@"1"]; [subscriber sendNext:@"2"]; [subscriber sendNext:@"3"]; [subscriber sendCompleted]; return [RACDisposable disposableWithBlock:^{}]; } |
这里只需要有个印象,参数是外部的一个block。
继续看RACDynamicSignal创建信号的过程:
@interface RACDynamicSignal () // The block to invoke for each subscriber. @property (nonatomic, copy, readonly) RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber); @end @implementation RACDynamicSignal #pragma mark Lifecycle + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe { RACDynamicSignal *signal = [[self alloc] init]; signal->_didSubscribe = [didSubscribe copy]; return [signal setNameWithFormat:@"+createSignal:"]; } // 其他暂时省略的代码。 @end |
通过这部分代码我们可以很清晰地看到,RACDynamicSignal这个类有一个block类型属性didSubscribe,并且在createSignal的时候将外部传递进来的参数:block对象,赋值给了这个didSubscribe属性。
到此为止。创建信号的过程结束。我们看到,这一步的核心动作是RACDynamicSignal这个类的对象去持有外部传进来的block类型的对象:didSubscribe。
看完创建信号的过程,接下来就是订阅这个信号了。
订阅信号
订阅信号的过程如下:
[signal subscribeNext:^(id _Nullable x) { NSLog(@"next: %@", x); } error:^(NSError * _Nullable error) { NSLog(@"error: %@", error); } completed:^{ NSLog(@"completed"); }]; |
然后我们再来看看RACSignal的subscribeNext相关的方法:
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock { NSCParameterAssert(nextBlock != NULL); NSCParameterAssert(errorBlock != NULL); NSCParameterAssert(completedBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock]; return [self subscribe:o]; } |
发现了一个RACSubscriber,看名字我们知道,这个才是真正的订阅者。订阅的时候,将这个订阅者作为参数传递给了signal的subscribe方法。继续看subscribe方法实现。
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { NSCAssert(NO, @"This method must be overridden by subclasses"); return nil; } |
哈哈,RACSignal的subscribe方法说,我没有实现,请找找我的子类实现吧。我们回头看看创建信号的时候,其实创建的是RACDynamicSignal类的对象。OK,我们看看RACDynamicSignal的subscribe实现。
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { NSCParameterAssert(subscriber != nil); 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; } |
我们先过滤掉暂时不关心的代码。看到这么一段调用:
RACDisposable *innerDisposable = self.didSubscribe(subscriber); |
额,绕来绕去,最终我们发现,订阅的过程实际上是去执行我们创建信号时,传递进去的block类型的参数。并且将RACSubscriber类型的对象subscriber作为参数传递进去了。并且注意到这个subscriber是遵循RACSubscriber协议的。
探究到底,我们再来看看RACSubscriber协议:
@protocol RACSubscriber <NSObject> @required /// 发送value给订阅者. /// /// value - 可以为nil的value. - (void)sendNext:(nullable id)value; /// 发送error给订阅者. /// /// error - 可以为nil的error. /// /// 当error发生的时候,会取消所有的订阅动作,订阅者将不再收到任何消息。 - (void)sendError:(nullable NSError *)error; /// 发送completed给订阅者 /// /// 当completed发生的时候,也会取消所有的订阅。 - (void)sendCompleted; /// 管理每一次订阅。 /// 告诉订阅者:发生了订阅行为。并将这次订阅行为相关的 `Disposable` 传给订阅者. /// 以便后续管理取消订阅的流程。 - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable; @end |
回过头来看看我们创建信号的过程。我们传递给RACDynamicSignal对象的block内就有发射value、completed。
[subscriber sendNext:@"1"]; [subscriber sendNext:@"2"]; [subscriber sendNext:@"3"]; [subscriber sendCompleted]; |
这里发送了三个value:@"1"、@"2"、@"3",以及一个completed。
到这里,订阅者接收了这几个value以及一个completed,订阅的过程基本结束了。还有一点,外部怎么拿到我们的这个value以及completed。留待下一节详细讲解。
到这里,总结一下信号创建及订阅的核心流程:
1、创建RACDynamicSignal信号。
2、并且将一个block类型的对象作为参数,传递给RACDynamicSignal对象的属性didSubscribe。
3、创建一个订阅者RACSubscriber,这个订阅者实现了RACSubscriber协议。
4、执行RACDynamicSignal对象的didSubscribe,并将第3步创建的订阅者作为参数传递给didSubscribe。
5、在didSubscribe这个block内部,传递进来的订阅者RACSubscriber发送value,或者发送error,或者发送completed消息。
6、实现了RACSubscriber协议的订阅者,转而通过自身的block属性,将value、error、completed传递给外部。
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。