RACReplaySubject
前面两篇文章,我们已经了解到了关于RACSignal和RACSubject的源码部分,并且,也已经了解这两个创建信号的方式的区别,今天我们来看一个RACSubject的相似类RACReplaySubject,这个类和之前类有什么区别???我们一个拭目以待!!!
实现代码
//1.重复信号
RACReplaySubject *replaySubject = [RACReplaySubject subject];
//3.发送信号
[replaySubject sendNext:@"1"];
//2.订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
RACReplaySubject 创建信号
与之前一样,我们还是先看看RACReplaySubject是如何创建对象的。与之前RACSubject相同,它们都是调用了subject类方法进行实例化对象的。具体原因如下:
@interface RACReplaySubject : RACSubject
/// Creates a new replay subject with the given capacity. A capacity of
/// RACReplaySubjectUnlimitedCapacity means values are never trimmed.
+ (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity;
官方定义中,我们清楚的看到,RACSReplaySubject是继承自RACSubject类的,因此,自然可以用父类的方法实力化自己了。在创建信号的subject中,之前分析到,这里面对订阅者做了定义,是一个订阅者数组。
RACReplaySubject 发送消息
首先,我们来正式看一下发送消息是如何处理的,在这里与之前的不同是调用顺序性对于RACReplaySubject来说变得无关紧要,也就是说:
- 先发送消息,后订阅信号
- 先订阅信号,后发送消息
其结果都是可以正常运行的,在成这样无序性的原因就是在发送消息中产生的。
思考: 为什么在发送消息中定义不同,而不在订阅信号时候进行处理???
个人认为,设计在sendText中的好处是当信号每次发送一个消息时候,就能够及时的把消息保存到一个消息数组,再根据响应式编程的思想,在订阅的时候,在遍历保存好信号消息的数组,就可以实现无序调用了,因为,只要数组一直被强引用,就不会被销毁,就可以直接访问里面的消息。
- (void)sendNext:(id)value {
@synchronized (self) {
[self.valuesReceived addObject:value ?: RACTupleNil.tupleNil];
[super sendNext:value];
if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
[self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
}
}
}
const NSUInteger RACReplaySubjectUnlimitedCapacity = NSUIntegerMax;
数据处理时候,利用同步锁防止数据处理问题。
self.valuesReceived 用于保存接受到的消息,但是不是直接存储,当value有值时候进行添加,否则传入nil。这里面没有直接用nil,而是用了RAC定义的元组nil(关于RAC远组后面会有讲解)。
在上面我们可以看到RACReplaySubjectUnlimitedCapacity定义的是最大值,只要不等于最大限度,就可以不断的添加消息。
之前实力化时候,capacity是1,表示自身一个,当接收消息的不断增多,每发送一个消息就会从数组中移除。
值得注意的是这里面有一个思想:
在子类对父类方法进行重写后,仍利用父类方法发送消息。
- (void)sendNext:(id)value {
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
}
- (void)sendNext:(id)value {
/* 发送信号可能会导致出现多个发送信号同时发送,出现交叉的情况。因此,需要使用同步锁 */
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
RACReplaySubject 订阅信号
与RACSubject同样,通过RACSubscriber进行信号的订阅。
至此,关于RACReplaySubject的源码解析就全部结束了,下一篇文章,我们会关注关于RAC提供的数组和字典的处理。
GitHub源码下载
中文解析ReactiveCocoa: Github.