通过下面一张图理解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过程的更多相关文章

  1. 一张图搞清楚PMBOK所有过程的使用

      很多参加PMP培训的学员大概都会有一个感受,上课时似乎每个知识点都听懂了,大的知识框架也弄明白了,但是所有这些串起来在实践中怎么用呀!说的再直接一点,在考试的时候这些过程和活动是以怎样的逻辑来应用 ...

  2. 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域

    × 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...

  3. 几张图理解Roll, Pitch, Yaw的含义

    Roll:翻滚    Pitch:俯仰    Yaw:偏航 有时候不知道它到底绕着哪个轴旋转得到的角,一个比较容易的记法是根据字母的排列顺序PRY分别对应XYZ轴进行旋转得到的角,即: Pitch是绕 ...

  4. 一张图理解prototype、proto和constructor的三角关系

    × 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 javascript里的关系又多又乱.作用域链是一种单向的链式关系,还算简单清晰:this机制的调用关系,稍微有些复杂:而关于原型,则 ...

  5. 8张图理解Java

    一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...

  6. 【转】8张图理解Java

    一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...

  7. [ImportNew]8张图理解Java

    http://www.importnew.com/11725.html 1.字符串的不变性. 下面这张图展示了这段代码做了什么 String s = "abcd"; s = s.c ...

  8. 8张图理解Java(转)

    一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...

  9. [转] 一张图理解prototype、proto和constructor的三角关系

    前面的话 javascript里的关系又多又乱.作用域链是一种单向的链式关系,还算简单清晰:this机制的调用关系,稍微有些复杂:而关于原型,则是prototype.proto和constructor ...

随机推荐

  1. 创建 Web 前端开发环境(node和npm以及git)

    Web 前端开发涉及多种工具,这里将常用工具的安装和配置进行说明,提供了详细的说明,为后继的开发创建一个坚实的基础. 本文介绍的工具有:NodeJS, NPM, Bower, Git 和 Grunt. ...

  2. Bonferroni校正法

    Bonferroni校正:如果在同一数据集上同时检验n个独立的假设,那么用于每一假设的统计显著水平,应为仅检验一个假设时的显著水平的1/n http://baike.baidu.com/view/12 ...

  3. IOS 使用GCD改善性能

    1.GCD介绍 GCD:Grand Central Dispathch,核心中央调度,是一种异步技术.但是它是系统级的. 负责管理队列,是线程之上的抽象层.队列可以并行或串行运行,能够在系统级自动管理 ...

  4. Selenium2(java)TestNG的使用 七

      TestNG,即Testing Next Generation,下一代测试技术,是一套根据JUnit和NUnit思想而构建的利用注释来强化测试功能的一个测试框架,即可以用来做单元测试,也可以用来做 ...

  5. 2.1. 托管对象模型是什么(Core Data 应用程序实践指南)

    托管对象模型是一种数据结构.在这里,数据结构.纲要.对象图.数据模型.托管对象模型这些术语是一个意思.它们是对同一个东西不同场景的描述.比如,对Core Data 而言是托管对象模型,对设计器来说是对 ...

  6. 转对象(含length属性)成数组Array.prototype.slice.call(arguments)

    我们知道,Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,除了IE下的节点集合(因为ie下的dom对象是以com对象的形式实现的,js ...

  7. CaltrainTimes从设计到发布(基于Flex的手机应用)

    资源下载地址 Caltrain Times 的 iTunes下载地址 Caltrain Times的Android Market 下载地址 Caltrain Times的BlackBerry App ...

  8. Java中泛型数组的使用

    package com.srie.testjava; import java.util.ArrayList; import java.util.List; public class TestClass ...

  9. HDU5726(RMQ&&二分)

    GCD Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status D ...

  10. oracle sql 知识小结

    Oracle_sql : 第一单元:select 语句: ①:字符串连接操作符: || ②:去除重复行:distinct   第二单元:条件限制和排序 ①:关键字:where ②:比较操作符:=,&g ...