RAC冷信号
2016-10-13 11:29
260 查看
概念
首先,信号使用发布订阅模式。冷信号:订阅者订阅了信号,它才会发布,并且立即把信号中的所有操作发布。
热信号:信号发布与订阅者订阅与否无关,订阅者可以在信号的发布过程中订阅。
例子分析
冷信号冷信号像调用函数一样,订阅就是去调用。看下面的代码:
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 4000 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来立即执行发布操作。
相关文章推荐
- RJ-45接口信号定义
- linux下基于C语言的信号编程实例
- RAC cache fusion机制实现原理分析
- Linux下的信号详解及捕捉信号
- oracle 11g RAC 常用命令整理分享
- Android实现信号强度监听的方法
- [Oracle] RAC 之 - 负载均衡深入解析
- Oracle11g RAC开启关闭、设置归档小结
- perl中使用signal(信号)实例
- ReactiveCocoa代码实践之-RAC网络请求重构
- ReactiveCocoa代码实践之-UI组件的RAC信号操作
- Linux线程同步之信号C语言实例
- 详解Python的Flask框架中的signals信号机制
- PyQt5每天必学之事件与信号
- RAC 中的双向数据绑定 RACChannel
- Shell脚本中信号处理实践
- ReactiveCocoa系列之signal流程详解
- 如何诊断RAC环境中节点重启问题(适用于10gR2和11gR1)
- 如何诊断RAC环境中节点重启问题(适用于11gR2)
- ORACLE RAC 日常管理[10g,11g]