RACSignal冷信号和热信号底层实现分析.docx
- 文档编号:2314195
- 上传时间:2023-05-03
- 格式:DOCX
- 页数:25
- 大小:538.37KB
RACSignal冷信号和热信号底层实现分析.docx
《RACSignal冷信号和热信号底层实现分析.docx》由会员分享,可在线阅读,更多相关《RACSignal冷信号和热信号底层实现分析.docx(25页珍藏版)》请在冰点文库上搜索。
RACSignal冷信号和热信号底层实现分析
RACSignal冷信号和热信号底层实现分析
前言
由于最近在写关于RACSignal底层实现分析的文章,当然也逃不了关于冷热信号操作的分析。
这篇文章打算分析分析如何从冷信号转成热信号的底层实现。
目录
1.关于冷信号和热信号的概念
2.RACSignal热信号
3.RACSignal冷信号
4.冷信号是如何转换成热信号的
一.关于冷信号和热信号的概念
冷热信号的概念是源自于源于.NET框架ReactiveExtensions(RX)中的HotObservable和ColdObservable,
HotObservable是主动的,尽管你并没有订阅事件,但是它会时刻推送,就像鼠标移动;而ColdObservable是被动的,只有当你订阅的时候,它才会发布消息。
HotObservable可以有多个订阅者,是一对多,集合可以与订阅者共享信息;而ColdObservable只能一对一,当有不同的订阅者,消息是重新完整发送。
热信号是主动的,即使你没有订阅事件,它仍然会时刻推送。
而冷信号是被动的,只有当你订阅的时候,它才会发送消息。
热信号可以有多个订阅者,是一对多,信号可以与订阅者共享信息。
而冷信号只能一对一,当有不同的订阅者,消息会从新完整发送。
二.RACSignal热信号
RACSignal家族中符合热信号的特点的信号有以下几个。
1.RACSubject
@interfaceRACSubject:
RACSignal
@property(nonatomic,strong,readonly)NSMutableArray*subscribers;
@property(nonatomic,strong,readonly)RACCompoundDisposable*disposable;
-(void)enumerateSubscribersUsingBlock:
(void(^)(id
+(instancetype)subject;
@end
首先来看看RACSubject的定义。
RACSubject是继承自RACSignal,并且它还遵守RACSubscriber协议。
这就意味着它既能订阅信号,也能发送信号。
在RACSubject里面有一个NSMutableArray数组,里面装着该信号的所有订阅者。
其次还有一个RACCompoundDisposable信号,里面装着该信号所有订阅者的RACDisposable。
RACSubject之所以能称之为热信号,那么它肯定是符合上述热信号的定义的。
让我们从它的实现来看看它是如何符合的。
-(RACDisposable*)subscribe:
(id
NSCParameterAssert(subscriber!
=nil);
RACCompoundDisposable*disposable=[RACCompoundDisposablecompoundDisposable];
subscriber=[[RACPassthroughSubscriberalloc]initWithSubscriber:
subscribersignal:
selfdisposable:
disposable];
NSMutableArray*subscribers=self.subscribers;
@synchronized(subscribers){
[subscribersaddObject:
subscriber];
}
return[RACDisposabledisposableWithBlock:
^{
@synchronized(subscribers){
NSUIntegerindex=[subscribersindexOfObjectWithOptions:
NSEnumerationReversepassingTest:
^BOOL(id
returnobj==subscriber;
}];
if(index!
=NSNotFound)[subscribersremoveObjectAtIndex:
index];
}
}];
}
上面是RACSubject的实现,它和RACSignal最大的不同在这两行
NSMutableArray*subscribers=self.subscribers;
@synchronized(subscribers){
[subscribersaddObject:
subscriber];
}
RACSubject把它的所有订阅者全部都保存到了NSMutableArray的数组里。
既然保存了所有的订阅者,那么sendNext,sendError,sendCompleted就需要发生改变。
-(void)sendNext:
(id)value{
[selfenumerateSubscribersUsingBlock:
^(id
[subscribersendNext:
value];
}];
}
-(void)sendError:
(NSError*)error{
[self.disposabledispose];
[selfenumerateSubscribersUsingBlock:
^(id
[subscribersendError:
error];
}];
}
-(void)sendCompleted{
[self.disposabledispose];
[selfenumerateSubscribersUsingBlock:
^(id
[subscribersendCompleted];
}];
}
从源码可以看到,RACSubject中的sendNext,sendError,sendCompleted都会执行enumerateSubscribersUsingBlock:
方法。
-(void)enumerateSubscribersUsingBlock:
(void(^)(id
NSArray*subscribers;
@synchronized(self.subscribers){
subscribers=[self.subscriberscopy];
}
for(id
block(subscriber);
}
}
enumerateSubscribersUsingBlock:
方法会取出所有RACSubject的订阅者,依次调用入参的block()方法。
关于RACSubject的订阅和发送的流程可以参考第一篇文章,大体一致,其他的不同就是会依次对自己的订阅者发送信号。
RACSubject就满足了热信号的特点,它即使没有订阅者,因为自己继承了RACSubscriber协议,所以自己本身就可以发送信号。
冷信号只能被订阅了才能发送信号。
RACSubject可以有很多订阅者,它也会把这些订阅者都保存到自己的数组里。
RACSubject之后再发送信号,订阅者就如同一起看电视,播放过的节目就看不到了,发送过的信号也接收不到了。
接收信号。
而RACSignal发送信号,订阅者接收信号都只能从头开始接受,如同看点播节目,每次看都从头开始看。
2.RACGroupedSignal
@interfaceRACGroupedSignal:
RACSubject
@property(nonatomic,readonly,copy)id
+(instancetype)signalWithKey:
(id
@end
先看看RACGroupedSignal的定义。
RACGroupedSignal是在RACsignal这个方法里面被用到的。
-(RACSignal*)groupBy:
(id
(id(^)(idobject))transformBlock
在这个方法里面,sendNext里面最后里面是由RACGroupedSignal发送信号。
[groupSubjectsendNext:
transformBlock!
=NULL?
transformBlock(x):
x];
关于groupBy的详细分析请看这篇文章
3.RACBehaviorSubject
@interfaceRACBehaviorSubject:
RACSubject
@property(nonatomic,strong)idcurrentValue;
+(instancetype)behaviorSubjectWithDefaultValue:
(id)value;
@end
这个信号里面存储了一个对象currentValue,这里存储着这个信号的最新的值。
当然也可以调用类方法behaviorSubjectWithDefaultValue
+(instancetype)behaviorSubjectWithDefaultValue:
(id)value{
RACBehaviorSubject*subject=[selfsubject];
subject.currentValue=value;
returnsubject;
}
在这个方法里面存储默认的值,如果RACBehaviorSubject没有接受到任何值,那么这个信号就会发送这个默认的值。
当RACBehaviorSubject被订阅:
-(RACDisposable*)subscribe:
(id
RACDisposable*subscriptionDisposable=[supersubscribe:
subscriber];
RACDisposable*schedulingDisposable=[RACScheduler.subscriptionSchedulerschedule:
^{
@synchronized(self){
[subscribersendNext:
self.currentValue];
}
}];
return[RACDisposabledisposableWithBlock:
^{
[subscriptionDisposabledispose];
[schedulingDisposabledispose];
}];
}
sendNext里面会始终发送存储的currentValue值。
调用sendNext会调用RACSubject里面的sendNext,也会依次发送信号值给订阅数组里面每个订阅者。
当RACBehaviorSubject向订阅者sendNext的时候:
-(void)sendNext:
(id)value{
@synchronized(self){
self.currentValue=value;
[supersendNext:
value];
}
}
RACBehaviorSubject会把发送的值更新到currentValue里面。
下次发送值就会发送最后更新的值。
4.RACReplaySubject
constNSUIntegerRACReplaySubjectUnlimitedCapacity=NSUIntegerMax;
@interfaceRACReplaySubject:
RACSubject
@property(nonatomic,assign,readonly)NSUIntegercapacity;
@property(nonatomic,strong,readonly)NSMutableArray*valuesReceived;
@property(nonatomic,assign)BOOLhasCompleted;
@property(nonatomic,assign)BOOLhasError;
@property(nonatomic,strong)NSError*error;
+(instancetype)replaySubjectWithCapacity:
(NSUInteger)capacity;
@end
RACReplaySubject中会存储RACReplaySubjectUnlimitedCapacity大小的历史值。
+(instancetype)replaySubjectWithCapacity:
(NSUInteger)capacity{
return[(RACReplaySubject*)[selfalloc]initWithCapacity:
capacity];
}
-(instancetype)init{
return[selfinitWithCapacity:
RACReplaySubjectUnlimitedCapacity];
}
-(instancetype)initWithCapacity:
(NSUInteger)capacity{
self=[superinit];
if(self==nil)returnnil;
_capacity=capacity;
_valuesReceived=(capacity==RACReplaySubjectUnlimitedCapacity?
[NSMutableArrayarray]:
[NSMutableArrayarrayWithCapacity:
capacity]);
returnself;
}
在RACReplaySubject初始化中会初始化一个capacity大小的数组。
-(RACDisposable*)subscribe:
(id
RACCompoundDisposable*compoundDisposable=[RACCompoundDisposablecompoundDisposable];
RACDisposable*schedulingDisposable=[RACScheduler.subscriptionSchedulerschedule:
^{
@synchronized(self){
for(idvalueinself.valuesReceived){
if(compoundDisposable.disposed)return;
[subscribersendNext:
(value==RACTupleNil.tupleNil?
nil:
value)];
}
if(compoundDisposable.disposed)return;
if(self.hasCompleted){
[subscribersendCompleted];
}elseif(self.hasError){
[subscribersendError:
self.error];
}else{
RACDisposable*subscriptionDisposable=[supersubscribe:
subscriber];
[compoundDisposableaddDisposable:
subscriptionDisposable];
}
}
}];
[compoundDisposableaddDisposable:
schedulingDisposable];
returncompoundDisposable;
}
当RACReplaySubject被订阅的时候,会把valuesReceived数组里面的值都发送出去。
-(void)sendNext:
(id)value{
@synchronized(self){
[self.valuesReceivedaddObject:
value?
:
RACTupleNil.tupleNil];
[supersendNext:
value];
if(self.capacity!
=RACReplaySubjectUnlimitedCapacity&&self.valuesReceived.count>self.capacity){
[self.valuesReceivedremoveObjectsInRange:
NSMakeRange(0,self.valuesReceived.count-self.capacity)];
}
}
}
在sendNext中,valuesReceived会保存每次接收到的值。
调用super的sendNext,会依次把值都发送到每个订阅者中。
这里还会判断数组里面存储了多少个值。
如果存储的值的个数大于了capacity,那么要移除掉数组里面从0开始的前几个值,保证数组里面只装capacity个数的值。
RACReplaySubject和RACSubject的区别在于,RACReplaySubject还会把历史的信号值都存储起来发送给订阅者。
这一点,RACReplaySubject更像是RACSingnal和RACSubject的合体版。
RACSignal是冷信号,一旦被订阅就会向订阅者发送所有的值,这一点RACReplaySubject和RACSignal是一样的。
但是RACReplaySubject又有着RACSubject的特性,会把所有的值发送给多个订阅者。
当RACReplaySubject发送完之前存储的历史值之后,之后再发送信号的行为就和RACSubject完全一致了。
三.RACSignal冷信号
在ReactiveCocoav2.5中除了RACsignal信号以外,还有一些特殊的冷信号。
1.RACEmptySignal
@interfaceRACEmptySignal:
RACSignal
+(RACSignal*)empty;
@end
这个信号只有一个empty方法。
+(RACSignal*)empty{
#ifdefDEBUG
return[[[selfalloc]init]setNameWithFormat:
@"+empty"];
#else
staticidsingleton;
staticdispatch_once_tpred;
dispatch_once(&pred,^{
singleton=[[selfalloc]init];
});
returnsingleton;
#endif
}
在debug模式下,返回一个名字叫empty的信号。
在release模式下,返回一个单例的empty信号。
-(RACDisposable*)subscribe:
(id
NSCParameterAssert(subscriber!
=nil);
return[RACScheduler.subscriptionSchedulerschedule:
^{
[subscribersendCompleted];
}];
}
RACEmptySignal信号一旦被订阅就会发送sendCompleted。
2.RACReturnSignal
@interfaceRACReturnSignal:
RACSignal
@property(nonatomic,strong,readonly)idvalue;
+(RACSignal*)return:
(id)value;
@end
RACReturnSignal信号的定义也很简单,直接根据value的值返回一个RACSignal。
+(RACSignal*)return:
(id)value{
#ifndefDEBUG
if(value==RACUnit.defaultUnit){
staticRACReturnSignal*unitSingleton;
staticdispatch_once_tunitPred;
dispatch_once(&unitPred,^{
unitSingleton=[[selfalloc]init];
unitSingleton->_value=RACUnit.defaultUnit;
});
returnunitSingleton;
}elseif(value==nil){
staticRACReturnSignal*nilSingleton;
staticdispatch_once_tnilPred;
dispatch_once(&nilPred,^{
nilSingleton=[[selfalloc]init];
nilSingleton->_value=nil;
});
returnnilSingleton;
}
#endif
RACReturnSignal*signal=[[selfalloc]init];
signal->_value=value;
#ifdefDEBUG
[signalsetNameWithFormat:
@"+return:
%@",value];
#endif
returnsignal;
}
在debug模式下直接新建一个RACReturnSignal信号里面的值存储的是入参value。
在release模式下,会依照value的值是否是空,来新建对应的单例RACReturnSignal。
-(RACDisposable*)subscribe:
(id
NSCParameterAssert(subscriber!
=nil);
return[RACScheduler.subscriptionSchedulerschedule:
^{
[subscribersendNext:
self.value];
[subscribers
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- RACSignal 信号 底层 实现 分析
![提示](https://static.bingdoc.com/images/bang_tan.gif)