RACSignal操作的核心bind实现分析
先来说说bind函数的作用:
- 会订阅原始的信号。
- 任何时刻原始信号发送一个值,都会绑定的block转换一次。
- 一旦绑定的block转换了值变成信号,就立即订阅,并把值发给订阅者subscriber。
- 一旦绑定的block要终止绑定,原始的信号就complete。
- 当所有的信号都complete,发送completed信号给订阅者subscriber。
- 如果中途信号出现了任何error,都要把这个错误发送给subscriber
// 创建源信号
// 创建了一个 RACDynamicSignal 类型的信号,并将传入的代码块保存起来,留待以后调用。
1. RACSignal *signal = [RACSignal createSignal:
^RACDisposable *(id<RACSubscriber> subscriber)
{
//block1
8. [subscriber sendNext:@1];
[subscriber sendNext:@2];
[subscriber sendNext:@3];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"signal dispose");
}];
}];
//绑定源信号,生成绑定信号
//bind操作实际上是直接生成绑定信号并返回,并且在生成绑定信号传入的didSubscriber block代码块中,保存了bind传入的block,初始化了信号数组,并且订阅了源信号,针对源信号发送信号的流程做了一些处理。(此时未执行,订阅才执行)
2. RACSignal *bindSignal = [signal bind:^RACStreamBindBlock{
// block 2
6. return ^RACSignal *(NSNumber *value, BOOL *stop){
// block 3
10. value = @(value.integerValue * 2);
return [RACSignal return:value];
};
}];
//订阅绑定信号
//订阅绑定信号就是保存了nextBlock,并且创建订阅者,实现信号的didSubscriber block代码块。
4. [bindSignal subscribeNext:^(id x) {
// block 4
14. NSLog(@"subscribe value = %@", x);
}];
- (RACSignal *)bind:(RACStreamBindBlock (^)(void))block {
// block 5
3. return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
// block 6
5. RACStreamBindBlock bindingBlock = block();
NSMutableArray *signals = [NSMutableArray arrayWithObject:self];
void (^completeSignal)(RACSignal *, RACDisposable *) = ^(RACSignal *signal, RACDisposable *finishedDisposable) {
15. // block 7
};
void (^addSignal)(RACSignal *) = ^(RACSignal *signal) {
// block 8
12. RACDisposable *disposable = [signal subscribeNext:^(id x) {
// block 9
13. [subscriber sendNext:x];
} error:^(NSError *error) {
[compoundDisposable dispose];
[subscriber sendError:error];
} completed:^{
@autoreleasepool {
14. completeSignal(signal, selfDisposable);
}
}];
};
@autoreleasepool {
7. RACDisposable *bindingDisposable = [self subscribeNext:^(id x) {
// block 10
9. id signal = bindingBlock(x, &stop);
@autoreleasepool {
11. if (signal != nil) addSignal(signal);
if (signal == nil || stop) {
[selfDisposable dispose];
completeSignal(self, selfDisposable);
}
}
} error:^(NSError *error) {
[compoundDisposable dispose];
[subscriber sendError:error];
} completed:^{
@autoreleasepool {
completeSignal(self, selfDisposable);
}
}];
}
return compoundDisposable;
}] ;
}
bind底层实现分析:
-
序号1 .先创建信号
signal
,内部创建RACDynamicSignal
,属性didSubscribe
把block1
copy保存起来。返回一个RACDynamicSignal
. -
序号2 . 当signal信号调用
bind
进行绑定,会调用block5
, -
序号3 . [RACSignal createSignal] 内部会创建RACDynamicSignal用
didSubscribe
把block6
copy保存起来。返回一个RACDynamicSignal的bindSignal -
序号4 .当订阅者开始订阅bindSignal的时候,也就是
subscribeNext
内部会创建订阅者,然后self.didSubscribe(subscriber),即执行didSubscribe
的block,即执行block6
。 -
序号5 .在
block6
的第一句代码,即RACStreamBindBlock bindingBlock = block()
,这里的block是外面传进来的block2
,于是开始调用block2。 -
序号6 .执行完block2,会返回一个RACStreamBindBlock的对象。赋值给bindingBlock,bindingBlock就是block3,注意此时还没有执行block3,
-
序号7 .由于是源信号
signal
调用的bind函数,所以bind函数里面的self就是源信号signal,在bind内部订阅了源信号signal。内部会创建订阅者,订阅者里面用nextblock
属性保存了block10
,然后self.didSubscribe(subscriber)
。由于前面self.didSubscribe
存储的就是block1
,所以会执行block1。 -
序号8 .执行
block1
,sendNext
调用订阅者subscriber
的nextBlock
,于是开始执行block10
。 -
序号9 .
block10
中会先调用bindingBlock
,这个是之前调用block2的返回值,这个RACStreamBindBlock对象里面保存的是block3
。所以开始调用block3
。 -
序号10 . 在
block3
中入参是一个value
,这个value
是signal
中sendNext
中发出来的value
的值,在block3
中可以对value
进行变换,变换完成后,返回一个新的信号signal’
(类型为RACReturnSignal
)。 -
序号11 .如果返回的
signal'
为空,则会调用completeSignal
,即调用block7
。block7
中会发送sendCompleted
。如果返回的signal'
不为空,则会调用addSignal
,即调用block8。 -
序号12 .
block8
中会继续订阅signal'
。由于signal'
是外面bind
函数的返回值,返回值的信号是RACReturnSignal
类型的,所以一订阅就会sendNext
,就会执行block9
。 -
序号13 .
block9
中会sendNext
,这里的subscriber
是block6
的入参,于是对subscriber
调用sendNext
,会调用到bindSignal
的订阅者的block4
中。 -
序号14 .block9 中执行完sendNext,还会调用sendCompleted。这里的是在执行block9里面的completed闭包。
-
序号15 .
completeSignal(signal, selfDisposable)
;然后又会调用completeSignal
,即block7
。
执行完block7
,bind整个流程就完成了。
一句话总结:
bind
操作方法实质上就是生成新的绑定信号,利用returnSignal
作为中间信号来改变源数据生成新的数据并执行新绑定信号的nextBlock
代码块!