概述
RACSignal有很多的方法,包括对父类RACStream方法的实现、RACSignal.m中的方法、RACSignal+Operations.m中的方法,今天先分析下是如何实现RACStream中的方法的。
RACStream的介绍
打开RACStream.h文件,可以看到里面都很多的方法,然后打开RACStream.m里面,看看各个方法的调用,就会发现其实众多的方法最终都是调用了flattenMap:
和bind:
两个方法,而flattenMap:
里面也是调用了bind:
方法,所以重点还是要分析bind:
方法的实现。RACStream并没有对bind:
实现什么逻辑,所以还是要到RACSignal
中查看bind:
的实现。
RACSignal
中bind:
的实现
首先看下方法里面的注释:
/*
* -bind: should:
*
* 1. Subscribe to the original signal of values.
* 2. Any time the original signal sends a value, transform it using the binding block.
* 3. If the binding block returns a signal, subscribe to it, and pass all of its values through to the subscriber as they're received.
* 4. If the binding block asks the bind to terminate, complete the _original_ signal.
* 5. When _all_ signals complete, send completed to the subscriber.
*
* If any signal sends an error at any point, send that to the subscriber.
*/
翻译一下:
1. 订阅源信号的值
2. 不管源信号什么时候发送一个值,都使用 binding block 转换这个值。
3. 如果转换后的值是一个信号,订阅这个信号并将这个信号发送的值转换为订阅者需要接收的值。
4. 如果 binding block 想要终止 bind,源信号完成。
5. 当所有的信号完成了,给订阅者发送完成操作。
* 如果任何一个信号任何时间发送了一个错误,需要将这个错误发送给订阅者。
接着,看下代码具体操作:
* 首先通过createSignal:
重新创建了一个信号。然后在信号的_didSubscribe
中完成了所有的操作。
* _didSubscribe
中首先调用bind:
方法的参数block
获取到了RACStreamBindBlock
类型的bindingBlock
,RACStreamBindBlock
的定义为typedef RACStream * (^RACStreamBindBlock)(id value, BOOL *stop);
,有两个参数value
stop
和一个返回值RACStreamBindBlock
,具体使用会在下面的逻辑中体现出来。
* 接着创建了一个数组用来存放信号,初始化中存放了信号本身。NSMutableArray *signals = [NSMutableArray arrayWithObject:self];
* 创建一个整合清理对象RACCompoundDisposable
用于管理所有涉及到的清理对象。RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
。
* 接着一个completeSignal
块,用来处理完成逻辑。包含两个参数RACSignal *signal, RACDisposable *finishedDisposable
,首先将signal
移除,然后判断当前信号数组signals
的个数,如果一个信号都没有了,就发送完成信号,并将所有的清理对象全部清除。如果数组中还有其他信号的话,就移除该信号对应的清理对象。
* 接着是addSignal
块,用来处理信号的添加。包含一个参数RACSignal *signal
,首先将信号添加的数组中signals
,然后创建一个清理对象selfDisposable
并添加到compoundDisposable
中,接下来通过subscribeNext:error:completed:
完成对该信号的订阅,将该信号的值发送出去,如果遇到错误,将compoundDisposable
清除,然后发送错误信息。如果遇到完成信息,通过定义的completeSignal
块处理。
* 接下来就是对应源信号的订阅。首先还是创建一个对应于原信号的清理对象selfDisposable
并将其添加到整合清理对象compoundDisposable
中。接着在对源信号的订阅中,subscribeNext:
首先检查compoundDisposable
是否已经做了清理工作,然后调用bindingBlock
完成对信号值的转换,如果转换后的值是一个信号,调用addSignal
块将该信号处理,如果不是个信号或者得到的了终止信息,清理源信号并调用completeSignal
处理。error:
中调用整合清理对象的清理方法,并发送一个错误信息。completed
中还是调用completeSignal
块处理。
虽然是把整个方法从上到下分析了一遍,但是并没有跟注释对应上,所以,现在从注释的角度分享下代码。
1. 订阅源信号的值
这一点应该是不用说了,通过self subscribeNext:
订阅了源信号的值。
2. 不管源信号什么时候发送一个值,都使用 binding block 转换这个值。
看下源信号的订阅,subscribeNext:
中id signal = bindingBlock(x, &stop);
调用了bindingBlock
完成了对值的转换。
3. 如果转换后的值是一个信号,订阅这个信号并将这个信号发送的值转换为订阅者需要接收的值。
同样接着看subscribeNext:
,
if (signal != nil) addSignal(signal);
if (signal == nil || stop) {
[selfDisposable dispose];
completeSignal(self, selfDisposable);
}
这里检测signal != nil
,然后addSignal(signal)
。在addSignal
定义中signal subscribeNext:
完成了对signal
的订阅,并将值发送了出去。
4. 如果 binding block 想要终止 bind,源信号完成。
在看self subscribeNext:
中if (signal == nil || stop)
,如果stop
为YES
,就会调用[selfDisposable dispose];
完成对源信号的订阅。
5. 当所有的信号完成了,给订阅者发送完成操作。
查看completeSignal
块的定义,里面会判断当前信号的个数,如果没有了信号,就会发送完成信息并做清理工作。
* 如果任何一个信号任何时间发送了一个错误,需要将这个错误发送给订阅者。
首先看下源信号发生错误,会完成所有清理工作并发送错误信息。此时就算是signals
中还有其他的信号,也不会在发送任何信息,因为已经被compoundDisposable
作了清理。然后看下添加信号的订阅signal subscribeNext:error:
,错误的时候也会做清理工作并发送错误信息。此时如果源信号的订阅在继续,在self subscribeNext:
中会判断compoundDisposable.disposed
,防止继续发送信息。其实到这里,应该还是有个疑问就是,为什么对添加的信号里面没有做compoundDisposable.disposed
的校验呢?注释中说明// Manually check disposal to handle synchronous errors.
,我不明白具体是什么原因,目前感觉是没有必要的。
上面把bind:
方法的实现分析完了,然后回到RACStream
中查看flattenMap:
的实现。
- (instancetype)flattenMap:(RACStream * (^)(id value))block {
Class class = self.class;
return [[self bind:^{
return ^(id value, BOOL *stop) {
id stream = block(value) ?: [class empty];
NSCAssert([stream isKindOfClass:RACStream.class], @"Value returned from -flattenMap: is not a stream: %@", stream);
return stream;
};
}] setNameWithFormat:@"[%@] -flattenMap:", self.name];
}
可见,里面还是调用了bind:
方法,通过参数block
可以将原始信号发送的信息转换成一个信号并对其进行订阅。而block可以由外部决定怎么创建一个RACStream
。
最后
以上就是动听溪流为你收集整理的RACSignal的使用方法 - 对RACStream的实现(一)的全部内容,希望文章能够帮你解决RACSignal的使用方法 - 对RACStream的实现(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复