一张图理解RACSignal的Subscription过程
通过下面一张图理解RACSignal的调用过程:

创建signale
RACSignal通过子类[RACDynamicSignal createSignal:]方法获得Signal,并将disSubscribe这个block保存在Signal中。
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
创建subscriber
signal通过调用subscribeNext方法生成subscriber,并将next、error、completed block保存在subscriber中
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
RACSubscriber *subscriber = [[self alloc] init];
subscriber->_next = [next copy];
subscriber->_error = [error copy];
subscriber->_completed = [completed copy];
return subscriber;
}
进行subscribe
第二步创建subscriber之后调用signal的subscribe方法,并将创建的subscriber作为参数。
这一步会生成RACCompoundDisposable和RACPassthroughSubscriber对象。
- RACCompoundDisposable:RACDisposable的子类,可以加入多个RACDisposable对象。当RACCompoundDisposable对象被dispose的时候,会dispose容器内的所有RACDisposable对象。
- RACPassthroughSubscriber:分别保存对RACSignal,RACSubscriber,RACCompoundDisposable的引用。通过RACPassthroughSubscriber对象来转发给真正的Subscriber。
- (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;
}
执行disSubscribe block
RACSignal通过RACScheduler.subscriptionScheduler来执行闭包,disSubscribe真正被调用的的位置就是上一步的RACDisposable *innerDisposable = self.didSubscribe(subscriber);
- (RACDisposable *)schedule:(void (^)(void))block {
NSCParameterAssert(block != NULL);
if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
block();
return nil;
}
调用sendNext sendError sendCompleted
进入didSubscribe闭包后,调用sendNext:、sendError:、sendCompleted。由于第三步中将subscriber替换为RACPassthroughSubscriber对象,真正的subscriber被存储在RACPassthroughSubscriber对象中,即innerSubscriber,所以这一步的各种send方法其实是一个转发过程。
- (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];
}
- (void)sendError:(NSError *)error {
if (self.disposable.disposed) return;
if (RACSIGNAL_ERROR_ENABLED()) {
RACSIGNAL_ERROR(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString(error.description));
}
[self.innerSubscriber sendError:error];
}
- (void)sendCompleted {
if (self.disposable.disposed) return;
if (RACSIGNAL_COMPLETED_ENABLED()) {
RACSIGNAL_COMPLETED(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description));
}
[self.innerSubscriber sendCompleted];
}
执行next error completed闭包
通过调用innerSubscriber的sendNext:、sendError、和sendCompleted方法执行真正的subscriber中的next error completed闭包
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
- (void)sendError:(NSError *)e {
@synchronized (self) {
void (^errorBlock)(NSError *) = [self.error copy];
[self.disposable dispose];
if (errorBlock == nil) return;
errorBlock(e);
}
}
- (void)sendCompleted {
@synchronized (self) {
void (^completedBlock)(void) = [self.completed copy];
[self.disposable dispose];
if (completedBlock == nil) return;
completedBlock();
}
}
过程回顾
去掉中间的繁杂细节,大致过程如下:
1.通过createSignal生成信号
2.通过subscribeNext确定信号内容到来时的处理方式
3.didSubscribe block块中异步处理完毕之后,进行sendNext、sendError和sendCompleted自动处理
一张图理解RACSignal的Subscription过程的更多相关文章
- 一张图搞清楚PMBOK所有过程的使用
很多参加PMP培训的学员大概都会有一个感受,上课时似乎每个知识点都听懂了,大的知识框架也弄明白了,但是所有这些串起来在实践中怎么用呀!说的再直接一点,在考试的时候这些过程和活动是以怎样的逻辑来应用 ...
- 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域
× 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...
- 几张图理解Roll, Pitch, Yaw的含义
Roll:翻滚 Pitch:俯仰 Yaw:偏航 有时候不知道它到底绕着哪个轴旋转得到的角,一个比较容易的记法是根据字母的排列顺序PRY分别对应XYZ轴进行旋转得到的角,即: Pitch是绕 ...
- 一张图理解prototype、proto和constructor的三角关系
× 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 javascript里的关系又多又乱.作用域链是一种单向的链式关系,还算简单清晰:this机制的调用关系,稍微有些复杂:而关于原型,则 ...
- 8张图理解Java
一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...
- 【转】8张图理解Java
一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...
- [ImportNew]8张图理解Java
http://www.importnew.com/11725.html 1.字符串的不变性. 下面这张图展示了这段代码做了什么 String s = "abcd"; s = s.c ...
- 8张图理解Java(转)
一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...
- [转] 一张图理解prototype、proto和constructor的三角关系
前面的话 javascript里的关系又多又乱.作用域链是一种单向的链式关系,还算简单清晰:this机制的调用关系,稍微有些复杂:而关于原型,则是prototype.proto和constructor ...
随机推荐
- 一个异步任务接收两个url下载两个图片
有两个url,一个是下载用户头像的url,一个是下载用户上传图片的url,想要用一个异步任务同时下载这两个图片. 程序的下载任务是这么执行的,先接受url参数,然后调用 imgUrls = infoP ...
- Sigmoid函数
Sigmoid函数是一个S型函数. Sigmoid函数的数学公式为: 它是常微分方程 的一个解. Sigmoid函数具有如下基本性质: 定义域为 值域为, 为有界函数 函数在定义域内为连续和光滑函数 ...
- 创建TabBar
-(void)creatTabBarView { NSArray *imgArray=@[]; NSArray *selectImage=@[]; NSArray *names=@[]; for (i ...
- Eclipse常见操作
Eclipse打开Package Explorer Window > Show View > Other Java > Package Explorer 然后可以将其拖拽到Eclip ...
- 新手如何学习java(java学习建议路线图)
怎么学习Java,这是很多新手经常会问我的问题,现在我简单描述下一个Java初学者到就业要学到的一些东西: 首先要明白Java体系设计到得三个方面:J2SE,J2EE,J2ME(KJAVA). ...
- 日历视图(CalendarView)组件的功能和用法
日历视图(CalendarView)可用于显示和选择日期,用户既可选择一个日期,也可通过触摸来滚动日历.如果希望监控该组件的日历改变,可调用CalendarView的setOnDateChangeLi ...
- cgLib生成动态代理
package com.stono.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import ...
- promise/bluebird源码
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/bluebirdsource 本博客同步在http://www.cnb ...
- mesos 资源分配
Mesos 资源分配 众所周知, Mesos在运行时使用wDRF( Dominant Resource Fairness)算法进行一级资源分配, 通过应用程序(Framework)运行时使用资源进行二 ...
- mac下sublime 配置查看源码
sublime及package control的安装查看之前一篇文章:http://www.cnblogs.com/xdwa/p/5805101.html 安装ctags 安装完毕package co ...