RAC热信号
2016-10-18 14:24
106 查看
首先来看如下代码
发布信号:
订阅者:
输出
就这个例子我们来分析一下,首先创建一个信号,信号发布操作发送了三个数,先是立即发送1,之后过了1秒后发送2,过了2秒后发送3.
下面有两个订阅者分别来订阅,但是可以看到,订阅的信号不是开始创建的信号,而是connection的信号,显然这是不同的信号,那么随之而然的订阅的结果也有所不同,分析结果来看,收到的信息并不像订阅冷信号那样,订阅了才会立即发布,而且还是把所有的发布一遍,这里按照订阅的时序来看,信号一直在发布中,中间有订阅者来订阅,就会收到后续发布的内容。
可见,这符合热信号的概念。
下面来看
代码告诉我们,调用publish方法生成了RACMulticastConnection对象,将self也就是创建的signal,和RACSubject对象注入了进去。
可以想的到就是将signal和RACSubject对象保存下来,分别存为sourceSignal和signal成员,这里可以看到,这的signal其实是RACSubject而不是原来他建的信号了,而RACSubject的基类也正是RACSignal,之前有提过,这个基类有派生出来若干种的信号,而RACSubject正是其中比较重要的一个。
现在就明白了这个connectionSigal了,它是
接下来看connect
它其实就是将源信号订阅一下新信号,其实就是原来创建的RACDynamicSignal subscribe RACSubject。之前冷信号中提过,调用subscribe:方法就会立即触发发布者,调用发布操作的block,ok,到这里就知道了,实际上调了connect方法,就会立即发布,而与下面的订阅者没有关系。
而发布操作里 [subscriber sendNext:];的subscriber仍然是封装的RACPassthroughSubscriber,但最终真正调用的sendNext:正是RACSubject的sendNext:它和RACDynamicSignal的sendNext:是有所不同的,如下
可以看到它非常的简单,就是把自己的subscribers遍历了一遍,分别来对subscriber sendNext:。
现在只要搞明白这些subscribers是从哪里来的,那么整个流程就串起来了,我想大家也都想到了,就是下面的这些订阅者。
这里subscribeNext方法同样也是生成订阅者对象,然后去调用subscribe:方法
会发现这里的subscribe:与RACDynamicSignal的subscribe:就不同了,RACDynamicSignal里面会直接调用信号的发布block,而这里只是将订阅者加进subscribers数组。所以RACSubject的订阅方法不会直接触发发布,而是把订阅者缓存了起来。
触发发布的正是源信号订阅RACSubject的时候。
创建发布信号RACDynamicSignal
调用pubish生成RACMulticastConnection,其中生成了RACSubject中间对象
调用connect,RACDynamicSignal被RACSubject订阅,立即触发发布操作,block中的sendNext方法为RACSubject的sendNext,遍历subscrbers数组,分别触发。
调用RACSubject的subscribeNext生成订阅者,订阅RACSubject,将订阅block加入subscrbers数组。
所以,先加入到subscrbers数组中的subsciber先开始接收到发布信息,后加入的就后开始收。
发布信号:
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; [[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{ [subscriber sendNext:@2]; }]; [[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{ [subscriber sendNext:@3]; [subscriber sendCompleted]; }]; return nil; }]; RACMulticastConnection *connection = [signal publish]; [connection connect]; RACSignal *connectionSigal = connection.signal;
订阅者:
[connectionSigal subscribeNext:^(id x) { NSLog(@">>>>>> received: %@ from 1",x); }]; [[RACScheduler mainThreadScheduler] afterDelay:1.5 schedule:^{ [connectionSigal subscribeNext:^(id x) { NSLog(@">>>>>> received: %@ from 2",x); }]; }];
输出
>>>>>> received: 2 from 1 >>>>>> received: 3 from 1 >>>>>> received: 3 from 2
就这个例子我们来分析一下,首先创建一个信号,信号发布操作发送了三个数,先是立即发送1,之后过了1秒后发送2,过了2秒后发送3.
下面有两个订阅者分别来订阅,但是可以看到,订阅的信号不是开始创建的信号,而是connection的信号,显然这是不同的信号,那么随之而然的订阅的结果也有所不同,分析结果来看,收到的信息并不像订阅冷信号那样,订阅了才会立即发布,而且还是把所有的发布一遍,这里按照订阅的时序来看,信号一直在发布中,中间有订阅者来订阅,就会收到后续发布的内容。
可见,这符合热信号的概念。
程序分析
创建信号之前在冷信号时已经说过了,回顾一下,创建的信号其实是RACDynamicSignal,它将发布操作block保存下来,有订阅者调用subscribe:就会去调用这个block。下面来看
RACMulticastConnection *connection = [signal publish];
- (RACMulticastConnection *)publish { RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name]; RACMulticastConnection *connection = [self multicast:subject]; return connection; } - (RACMulticastConnection *)multicast:(RACSubject *)subject { [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name]; RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject]; return connection; }
代码告诉我们,调用publish方法生成了RACMulticastConnection对象,将self也就是创建的signal,和RACSubject对象注入了进去。
- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject { NSCParameterAssert(source != nil); NSCParameterAssert(subject != nil); self = [super init]; if (self == nil) return nil; _sourceSignal = source; _serialDisposable = [[RACSerialDisposable alloc] init]; _signal = subject; return self; }
可以想的到就是将signal和RACSubject对象保存下来,分别存为sourceSignal和signal成员,这里可以看到,这的signal其实是RACSubject而不是原来他建的信号了,而RACSubject的基类也正是RACSignal,之前有提过,这个基类有派生出来若干种的信号,而RACSubject正是其中比较重要的一个。
RACSignal *connectionSigal = connection.signal;
现在就明白了这个connectionSigal了,它是
[RACSubject subject]
接下来看connect
//RACMuticastConnection - (RACDisposable *)connect { BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected); if (shouldConnect) { self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal]; } return self.serialDisposable; }
它其实就是将源信号订阅一下新信号,其实就是原来创建的RACDynamicSignal subscribe RACSubject。之前冷信号中提过,调用subscribe:方法就会立即触发发布者,调用发布操作的block,ok,到这里就知道了,实际上调了connect方法,就会立即发布,而与下面的订阅者没有关系。
而发布操作里 [subscriber sendNext:];的subscriber仍然是封装的RACPassthroughSubscriber,但最终真正调用的sendNext:正是RACSubject的sendNext:它和RACDynamicSignal的sendNext:是有所不同的,如下
- (void)sendNext:(id)value { [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) { [subscriber sendNext:value]; }]; } - (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block { NSArray *subscribers; @synchronized (self.subscribers) { subscribers = [self.subscribers copy]; } for (id<RACSubscriber> subscriber in subscribers) { block(subscriber); } }
可以看到它非常的简单,就是把自己的subscribers遍历了一遍,分别来对subscriber sendNext:。
现在只要搞明白这些subscribers是从哪里来的,那么整个流程就串起来了,我想大家也都想到了,就是下面的这些订阅者。
[connectionSigal subscribeNext:^(id x) { NSLog(@">>>>>> received: %@ from 1",x); }];
这里subscribeNext方法同样也是生成订阅者对象,然后去调用subscribe:方法
//RACSubject中 - (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 addObject:subscriber]; } return [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]; } }]; }
会发现这里的subscribe:与RACDynamicSignal的subscribe:就不同了,RACDynamicSignal里面会直接调用信号的发布block,而这里只是将订阅者加进subscribers数组。所以RACSubject的订阅方法不会直接触发发布,而是把订阅者缓存了起来。
触发发布的正是源信号订阅RACSubject的时候。
总结
通过上面的分析,估计又有点糊涂了,简单的总结一下:创建发布信号RACDynamicSignal
调用pubish生成RACMulticastConnection,其中生成了RACSubject中间对象
调用connect,RACDynamicSignal被RACSubject订阅,立即触发发布操作,block中的sendNext方法为RACSubject的sendNext,遍历subscrbers数组,分别触发。
调用RACSubject的subscribeNext生成订阅者,订阅RACSubject,将订阅block加入subscrbers数组。
所以,先加入到subscrbers数组中的subsciber先开始接收到发布信息,后加入的就后开始收。
相关文章推荐
- 系统信号表格和一些资料
- QT 子窗口监听主窗口信号(超级简单,但是好用,比如主窗口移动的时候,子窗口不要再继续处理任务)
- QRadioButton类中Toggled()信号的使用方法
- Linux C--信号 sigaction函数
- 高速电子线路的信号完整性设计(一)
- 信号和槽有一个非常精炼的C++实现,作者是Sarah Thompson,该实现只有一个头文件sigslot.h,跨平台且线程安全
- linux信号的机制
- 信号的抽取和插值
- linux中脚本扑捉(trap)信号问题
- hjr-通信原理(三):模拟信号数字载波编码
- 通信系统概论---模拟与数字信号基础
- Linux基础篇——信号
- 深入了解信号与槽
- 液晶面板的同步信号模式与定时
- Linux 进程通信之 ——信号和信号量总结
- 【Qt】2.2 继续了解信号和槽
- 诺基亚没信号,国产机有信号的思考
- QT的信号与槽机制介绍
- Linux c 信号—pause、sigsuspend 的相同于区别
- 线程与信号