概念
首先,信号使用发布订阅模式。
冷信号:订阅者订阅了信号,它才会发布,并且立即把信号中的所有操作发布。
热信号:信号发布与订阅者订阅与否无关,订阅者可以在信号的发布过程中订阅。
例子分析
- 冷信号
冷信号像调用函数一样,订阅就是去调用。看下面的代码:
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
[subscriber sendNext:@3];
[subscriber sendCompleted];
return nil;
}];
[signal subscribeNext:^(id x) {
NSLog(@"Subscriber 1 receive: %@", x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"Subscriber 2 receive: %@", x);
}];
输出如下:
Subscriber 1 receive: 1
Subscriber 1 receive: 2
Subscriber 1 receive: 3
Subscriber 2 receive: 1
Subscriber 2 receive: 2
Subscriber 2 receive: 3
可以看到,我们创建了一个发布信号(发布者),它做了什么事情呢?它就是对其订阅者发送了三次数字。
谁是订阅者呢,signal的subscribeNext即为订阅者,在下面的程序分析中可以看到subscribeNext方法内部创建了subscriber对象。
RAC是函数式编程,所以发布者的操作和订阅者的操作都以block参数的形式分别传入。
OK,看程序的输出可以看出,就像之前提到的那样,订阅了信号后,发布者会立即执行发布,像调了函数一样。那么内部是怎样做的呢?
一步步来看,先看创建发布信号:
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
可以看出createSignal的信号类型是RACDynamicSignal,那么它的createSignal:是怎么初始化的呢?
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
可以看到只是初始化了signal对象,而signal的_didSubscribe成员保存下了发布block。
下面看发布信号的发布内容:
在程序可以看到subscriber sendNext,subscriber是符合RACSubscriber协议的对象,那么就可能有很多种的订阅者,这个发布block做的就是调用每个订阅者sendNext。
这里我们先知道了这个订阅者类型是RACPassthroughSubscriber
//RACPassthroughSubscriber中
- (void)sendNext:(id)value {
if (self.disposable.disposed) return;
if (RACSIGNAL_NEXT_ENABLED()) {
RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description]));
}
[self.innerSubscriber sendNext:value];
}
innerSubscriber其实就是封装后又起了个名子的订阅者,也就是下面的真正订阅者。这里innerSubscriber sendNext:如下
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
真正的sendNext只做了简单的事,就是执行nextBlock(value),nextBlock是谁呢?可以猜到,下面的RACSubscriber要subscribeNext,是的,这个nextBlock就是subscribeNext的block。
最后来看订阅者:
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
可以看到,订阅block先生成订阅者RACSubscriber,然后把nextBlock等各订阅block保存下来。
然后[self subscribe:o],self是信号,o是RACSubscriber,
在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;
}
OK,我们看到了RACPassthroughSubscriber,就是上面发布信号发布操作里的subscriber,对真正订阅者重新封装了一下。
接下来的self.didSubscribe(subscriber);是真正执行信号发布操作block的地方,回顾一下,是上面的signal->_didSubscribe = [didSubscribe copy]; 命名上已经告诉我们了,didSubscribe,订阅完毕,该发布了。
其中RACDisposable是释放相关的,我们以后再讲。
总结
好了,跟着这几行代码走了下来,是不是有点糊涂了,那就总结一下流程,并调整一下上面的顺序。
信号的订阅—发布
- 创建发布者信号RACSignal(其实是RACDynamicSignal)
- 发布block传入,保存命名为didSubscribe
- 订阅block传入,subscribeNext:方法内部生成subscriber对象,并与订阅block封装成RACPassthroughSubscriber
- subscribeNext:方法内,由信号调用subscibe:方法来使得订阅者订阅信号。
- subscibe:方法内调用发布block didSubscribe来立即执行发布操作。