RACSignal
信号是ReactiveCocoa
中最基础概念之一就是。其中信号的实例为RACRACStream
.它两个子类RACSignal
和 RACSequence
.其中RACSequence
用的较少。本次只分析RACSignal
。
1 | RACSignal *signal = [RACSignal createSignal: |
试分析下。以上代码分别作了什么。首先这是一个RACSignal
作用的过程。
当调用了RACSignal
中createSignal
函数的时候,会调用RACSignal
的子类RACDynamicSignal
的createSignal
函数。
1 | + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe { |
而 RACDynamicSignal
中 createSignal
的函数做了什么呢?
1 | @implementation RACDynamicSignal |
可以通过源码看出。只是生成了一个实例。保存了传入的 didSubscribe
。此时需要注意didSubscribe
的类型。首先它是一个 block
。他的参数是id<RACSubscriber>
返回值是RACDisposable
。那么现在我们已经保存了传入的didSubscribe
。现在我们需要找到它执行的时机。
首先我们找到RACSignal (Subscription)
这个RACSignal
的分类。
1 | @implementation RACSignal (Subscription) |
可以看到在信号被订阅的时候统一都生成了一个RACSubscriber
。并通过[self subscribe:o]
传递下去。接下来我们来看RACDynamicSignal
中subscribe
这个函数的实现。
1 | @implementation RACDynamicSignal |
通过代码可以看到。调用了保存下来的didSubscribe
这个block
,同时将传入进来的subscriber
当成参数传入进去。此时。我们便能确定。订阅式生成的subscriber
和我们创建信号的传进来的subscriber
。其实是同一个对象。那么接下来。我们来看下RACSubscriber
到底作了什么。
1 | @interface RACSubscriber () |
此时再看示例代码。就简单明了了。整体的流程也就是分成以下几个部分。
1 | RACSignal *signal = [RACSignal createSignal: |
- 创建新号。同时保存
subscriber
。等待信号被订阅是调用。 - 信号被订阅时,创建一个
RACSubscriber
实例.将订阅是传入的next
error
completed
回调事件保存在创建的RACSubscriber
实例中。 - 将创建的
RACSubscriber
实例传入创建信号是保存的subscriber
block
中 - 当
RACSubscriber
被调用对应的函数的时候。内部调用对应保存的block
。
基础使用原理分析
concat
1 | - (RACSignal *)concat:(RACSignal *)signal { |
调用concat
时。首先创建了一个新的信号。订阅了第一个信号。当第一个信号结束的时候。开始订阅第二个信号。并将两个信号传递的消息通过新创建的信号的订阅者发送出去。
zipWith
1 | - (RACSignal *)zipWith:(RACSignal *)signal { |
原理和concat
类似。创建新的信号。订阅传递进来的两个信号。匹配数据。通过新的信号的订阅者将组合好的数据发送出去。
bind
1 | - (RACSignal *)bind:(RACSignalBindBlock (^)(void))block { |
- 订阅当前的信号.
- 任何时候当前信号发送了一个数据,使用绑定的 block 转换它。
- 如果返回的是一个信号的话就订阅它。并在接收到数据时将其所有值传递给订阅者。
- 如果返回值要求停止则完成当前信号。
- 如果所有的信号都已经发送完毕。发送完成给当前订阅者。
- 如果信号发送的 error,将其转发给当前订阅者.
merge flaten
1 | + (RACSignal *)merge:(id<NSFastEnumeration>)signals { |
此处文字描述较为复杂。我会尽力说明。
- 调用 merge 的时候创建了一个新的信号,我们将其命名为 new_merge_signal.
- new_merge_signal 在被调用的时候。通过订阅者将需要 merge 的信号全部发送出去。
- new_merge_signal 主动调用了 flatten ,而 flatten 调用了 falttenMap。
- flattenMap 调用了 bind。
- bind 创建了一个新的信号,我们将其命名为 new_bind_signal。
- new_bind_signal 在被订阅的时候会主动订阅 new_merge_signal。new_merge_signal 在被订阅的时候会将所有需要 merge 的 signal 发送出去。 new_bind_signal 内部拿到需要 merge 的 signal 之后订阅所有需要合并的 signal。并将这些需要合并的 signal 发送的数据通过 new_bind_signal 的订阅者发送出去。