您的位置:首页 > 移动开发 > IOS开发

RAC热信号

2016-10-18 14:24 106 查看
首先来看如下代码

发布信号:

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
[subscriber sendNext:@2];
}];
[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
[subscriber sendNext:@3];
[subscriber sendCompleted];
}];
return nil;
}];
RACMulticastConnection *connection = [signal publish];
[connection connect];

RACSignal *connectionSigal = connection.signal;


订阅者:

[connectionSigal subscribeNext:^(id x) {
NSLog(@">>>>>> received: %@ from 1",x);
}];

[[RACScheduler mainThreadScheduler] afterDelay:1.5 schedule:^{
[connectionSigal subscribeNext:^(id x) {
NSLog(@">>>>>> received: %@ from 2",x);
}];
}];


输出

>>>>>> received: 2 from 1
>>>>>> received: 3 from 1
>>>>>> received: 3 from 2


就这个例子我们来分析一下,首先创建一个信号,信号发布操作发送了三个数,先是立即发送1,之后过了1秒后发送2,过了2秒后发送3.

下面有两个订阅者分别来订阅,但是可以看到,订阅的信号不是开始创建的信号,而是connection的信号,显然这是不同的信号,那么随之而然的订阅的结果也有所不同,分析结果来看,收到的信息并不像订阅冷信号那样,订阅了才会立即发布,而且还是把所有的发布一遍,这里按照订阅的时序来看,信号一直在发布中,中间有订阅者来订阅,就会收到后续发布的内容。

可见,这符合热信号的概念。

程序分析

创建信号之前在冷信号时已经说过了,回顾一下,创建的信号其实是RACDynamicSignal,它将发布操作block保存下来,有订阅者调用subscribe:就会去调用这个block。

下面来看
RACMulticastConnection *connection = [signal publish];


- (RACMulticastConnection *)publish {
RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
RACMulticastConnection *connection = [self multicast:subject];
return connection;
}

- (RACMulticastConnection *)multicast:(RACSubject *)subject {
[subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
return connection;
}


代码告诉我们,调用publish方法生成了RACMulticastConnection对象,将self也就是创建的signal,和RACSubject对象注入了进去。

- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
NSCParameterAssert(source != nil);
NSCParameterAssert(subject != nil);

self = [super init];
if (self == nil) return nil;

_sourceSignal = source;
_serialDisposable = [[RACSerialDisposable alloc] init];
_signal = subject;

return self;
}


可以想的到就是将signal和RACSubject对象保存下来,分别存为sourceSignal和signal成员,这里可以看到,这的signal其实是RACSubject而不是原来他建的信号了,而RACSubject的基类也正是RACSignal,之前有提过,这个基类有派生出来若干种的信号,而RACSubject正是其中比较重要的一个。

RACSignal *connectionSigal = connection.signal;


现在就明白了这个connectionSigal了,它是
[RACSubject subject]


接下来看connect

//RACMuticastConnection
- (RACDisposable *)connect {
BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);

if (shouldConnect) {
self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];
}

return self.serialDisposable;
}


它其实就是将源信号订阅一下新信号,其实就是原来创建的RACDynamicSignal subscribe RACSubject。之前冷信号中提过,调用subscribe:方法就会立即触发发布者,调用发布操作的block,ok,到这里就知道了,实际上调了connect方法,就会立即发布,而与下面的订阅者没有关系。

而发布操作里 [subscriber sendNext:];的subscriber仍然是封装的RACPassthroughSubscriber,但最终真正调用的sendNext:正是RACSubject的sendNext:它和RACDynamicSignal的sendNext:是有所不同的,如下

- (void)sendNext:(id)value {
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
}
- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
NSArray *subscribers;
@synchronized (self.subscribers) {
subscribers = [self.subscribers copy];
}

for (id<RACSubscriber> subscriber in subscribers) {
block(subscriber);
}
}


可以看到它非常的简单,就是把自己的subscribers遍历了一遍,分别来对subscriber sendNext:。

现在只要搞明白这些subscribers是从哪里来的,那么整个流程就串起来了,我想大家也都想到了,就是下面的这些订阅者。

[connectionSigal subscribeNext:^(id x) {
NSLog(@">>>>>> received: %@ from 1",x);
}];


这里subscribeNext方法同样也是生成订阅者对象,然后去调用subscribe:方法

//RACSubject中
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);

RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

NSMutableArray *subscribers = self.subscribers;
@synchronized (subscribers) {
[subscribers addObject:subscriber];
}

return [RACDisposable disposableWithBlock:^{
@synchronized (subscribers) {
// Since newer subscribers are generally shorter-lived, search
// starting from the end of the list.
NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
return obj == subscriber;
}];

if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
}
}];
}


会发现这里的subscribe:与RACDynamicSignal的subscribe:就不同了,RACDynamicSignal里面会直接调用信号的发布block,而这里只是将订阅者加进subscribers数组。所以RACSubject的订阅方法不会直接触发发布,而是把订阅者缓存了起来。

触发发布的正是源信号订阅RACSubject的时候。

总结

通过上面的分析,估计又有点糊涂了,简单的总结一下:

创建发布信号RACDynamicSignal

调用pubish生成RACMulticastConnection,其中生成了RACSubject中间对象

调用connect,RACDynamicSignal被RACSubject订阅,立即触发发布操作,block中的sendNext方法为RACSubject的sendNext,遍历subscrbers数组,分别触发。

调用RACSubject的subscribeNext生成订阅者,订阅RACSubject,将订阅block加入subscrbers数组。

所以,先加入到subscrbers数组中的subsciber先开始接收到发布信息,后加入的就后开始收。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  RAC 热信号 iOS ObjC