ReactiveCocoa源码精讲(三) -- RACReplaySubject

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来说变得无关紧要,也就是说:

  1. 先发送消息,后订阅信号
  2. 先订阅信号,后发送消息
    其结果都是可以正常运行的,在成这样无序性的原因就是在发送消息中产生的。

思考: 为什么在发送消息中定义不同,而不在订阅信号时候进行处理???
个人认为,设计在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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值