ReactiveCocoa源码解读(二)
来源:互联网 发布:手游藕丝步云履数据 编辑:程序博客网 时间:2024/06/07 03:44
上一篇解读了ReactiveCocoa
的三个重要的类的底层实现,本篇继续。
一、RACMulticastConnection
1.应用
RACMulticastConnection
: 用于当一个信号被多次订阅时,为了保证创建信号时,避免多次调用创建信号的block造成副作用,可以使用该类处理,保证创建信号的block执行一次。
// 创建信号RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) { NSLog(@"发送请求"); [subscriber sendNext:@1]; return nil;}];// 创建连接RACMulticastConnection *connect = [signal publish];// 订阅连接的信号[connect.signal subscribeNext:^(id x) { NSLog(@"connect 第一次订阅信号: %@", x);}];[connect.signal subscribeNext:^(id x) { NSLog(@"connect 第二次订阅信号: %@", x);}];// 连接[connect connect];
2.源码实现
- 底层原理
1.创建connect,connect.sourceSignal -> RACSignal(原始信号) connect.signal -> RACSubject2.订阅connect.signal,会调用RACSubject的subscribeNext,创建订阅者,而且把订阅者保存起来,不会执行block。3.[connect connect]内部会订阅RACSignal(原始信号),并且订阅者是RACSubject 3.1.订阅原始信号,就会调用原始信号中的didSubscribe 3.2 didSubscribe,拿到订阅者调用sendNext,其实是调用RACSubject的sendNext4.RACSubject的sendNext,会遍历RACSubject所有订阅者发送信号。 4.1 因为刚刚第二步,都是在订阅RACSubject,因此会拿到第二步所有的订阅者,调用他们的nextBlock
- 创建信号
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
// RACDynamicSignal.m+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe { RACDynamicSignal *signal = [[self alloc] init]; //将代码块保存到信号里面(但此时仅仅是保存,没有调用),所以信号还是冷信号 signal->_didSubscribe = [didSubscribe copy]; return [signal setNameWithFormat:@"+createSignal:"];}
- 创建连接
[signal publish]
// RACSignal+Operations.m- (RACMulticastConnection *)publish { // 创建订阅者 RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name]; // 创建connection,参数是刚才创建的订阅者 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;}// RACMulticastConnection.m- (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是RACSubject对象 _signal = subject; return self;}
- 订阅信号
(RACDisposable *)subscribeNext:(void (^ )(id x))nextBlock;
// RACSignal.m- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock { NSCParameterAssert(nextBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL]; return [self subscribe:o];}// RACSubscriber.m+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed { RACSubscriber *subscriber = [[self alloc] init]; subscriber->_next = [next copy]; subscriber->_error = [error copy]; subscriber->_completed = [completed copy]; return subscriber;}// RACSubject.m- (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]; } }];}
- 连接信号
[connect connect];
// RACMulticastConnection.m- (RACDisposable *)connect { BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected); if (shouldConnect) { // 订阅原生信号 self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal]; } return self.serialDisposable;}// RACDynamicSignal.m- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { NSCParameterAssert(subscriber != nil); RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable]; if (self.didSubscribe != NULL) { RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{ RACDisposable *innerDisposable = self.didSubscribe(subscriber); [disposable addDisposable:innerDisposable]; }]; [disposable addDisposable:schedulingDisposable]; } return disposable;}// RACSubject.m- (void)sendNext:(id)value { // 遍历_subscribers数组,执行nextBlock [self enumerateSubscribersUsingBlock:^(id subscriber) { [subscriber sendNext:value]; }];}
3.流程图
4.总结
RACMulticastConnection
利用RACSubject
实现了创建信号的block
只执行一次的功能。对于需要对此订阅信号,但是不希望多次创建信号的应用场合,可以RACMulticastConnection
解决。
二、RACCommand
1.应用
RACCommand
类用来表示动作的执行, 是对动作触发后的连锁事件的封装。常用在封装网络请求,按钮点击等等场合。
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { return [RACSignal createSignal:^RACDisposable *(id subscriber) { if (/* DISABLES CODE */ (YES)) { // 正常发送数据,必须发送完成信号 [subscriber sendNext:@"Smile"]; [subscriber sendCompleted]; } else { // 发送错误信号 [subscriber sendError:[NSError errorWithDomain:@"Network failed" code:0005 userInfo:nil]]; } // 信号被销毁前,做一些清理的工作;如果不需要,可以 return nil return [RACDisposable disposableWithBlock:^{ NSLog(@"信号被销毁了"); }]; }];}];// 执行信号并订阅[[command execute:nil] subscribeNext:^(id x) { NSLog(@"receive data: %@", x);}];
2.源码实现
RACCommand底层实现
1. 创建命令,保存signalBlock2. 执行命令* 2.1 调用signalBlock* 2.2 创建connect,传入RACReplaySubject对象,然后连接信号3. 订阅信号* 3.1 创建订阅者,保存到RACReplaySubject对象的_subscribers数组中* 3.2 遍历valuesReceived数组,调用订阅者发送数据
- 创建command
- (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
// RACCommand.m- (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock { return [self initWithEnabled:nil signalBlock:signalBlock];}- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock { NSCParameterAssert(signalBlock != nil); self = [super init]; if (self == nil) return nil; _activeExecutionSignals = [[NSMutableArray alloc] init]; // 保存创建信号的block _signalBlock = [signalBlock copy]; ......}
- 执行command
- (RACSignal *)execute:(id)input
// RACCommand.m- (RACSignal *)execute:(id)input { // `immediateEnabled` is guaranteed to send a value upon subscription, so // -first is acceptable here. BOOL enabled = [[self.immediateEnabled first] boolValue]; if (!enabled) { NSError *error = [NSError errorWithDomain:RACCommandErrorDomain code:RACCommandErrorNotEnabled userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(@"The command is disabled and cannot be executed", nil), RACUnderlyingCommandErrorKey: self }]; return [RACSignal error:error]; } RACSignal *signal = self.signalBlock(input); ...... // 创建连接,用RACReplaySubject作为订阅者 RACMulticastConnection *connection = [[signal subscribeOn:RACScheduler.mainThreadScheduler] multicast:[RACReplaySubject subject]]; ...... // 连接信号 [connection connect]; return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, [input rac_description]];}// RACMulticastConnection.m- (RACDisposable *)connect { BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected); if (shouldConnect) { // 执行创建信号的block self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal]; } return self.serialDisposable;}
- 订阅command
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// RACSignal.m- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock { NSCParameterAssert(nextBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL]; return [self subscribe:o];}// RACReplaySubject.m- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{ @synchronized (self) { for (id value in self.valuesReceived) { if (compoundDisposable.disposed) return; // 调用订阅者,发送数据 "Smile" [subscriber sendNext:(value == RACTupleNil.tupleNil ? nil : value)]; } if (compoundDisposable.disposed) return; if (self.hasCompleted) { [subscriber sendCompleted]; } else if (self.hasError) { [subscriber sendError:self.error]; } else { // 调用父类方法,保存订阅者到_subscribers数组 RACDisposable *subscriptionDisposable = [super subscribe:subscriber]; [compoundDisposable addDisposable:subscriptionDisposable]; } } }]; [compoundDisposable addDisposable:schedulingDisposable]; return compoundDisposable;}
3.流程图
4.总结
RACCommand
用来封装事件时,还可以订阅信号(executionSignals
)、订阅最新信号(switchToLatest
)、跳过几次信号(skip
)或信号是否正在执行(executing
),在执行信号时,还可以监听错误信号和完成信号,请参考demo例子。
ReactiveCocoa
框架的源码分析暂告一段落,如有分析不足之处,欢迎互相交流。
Demo地址:
RACDemo
- ReactiveCocoa源码解读(二)
- ReactiveCocoa源码解读(一)
- RequireJS源码解读(二)
- ReactiveCocoa学习(二)
- Caffe源码解读(二):Blob类的源码解读
- Ext4.0源码解读(分享二)
- android-async-http源码解读(二)
- MPAndroidChart系列源码解读(二)
- jquery3.0源码解读(二)Extend
- SpringSecurity源码解读(二) successHandler
- SEDA源码解读(二)
- MINA源码解读(二)
- THUCTC源码解读(二)
- jQuery源码解读二
- jQuery源码解读二
- hadoop源码解读二
- ReactiveCocoa应用篇(二)
- ReactiveCocoa<二>
- Android Studio利用快捷键提高代码效率的方法(鸿洋大婶的~)
- java大数例题
- 关于百度云订阅无法正常查看订阅者分享的解决办法
- 初识单例模式——Android设计模式
- 表单
- ReactiveCocoa源码解读(二)
- [日常训练] 魔法传输
- 7.19 Allowance(贪心,*******思路理顺)
- 【loj】#6007. 「网络流 24 题」方格取数(二分图最大点权独立集)
- hibernate继承结构中每个类一张表
- 企业架构培训:为什么首先要建立和优化目标?
- 机器学习实战【3】(朴素贝叶斯)
- 数据库概念
- Centos 7.3 install Ambari2.5