RACSubject
//创建信号
RACSubject *subject = [RACSubject subject];
//订阅信号
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribeNext %@",x);
}];
//发送信号
[subject sendNext:@"1"];
分析
step1:
先看下RACSubject
@interface RACSubject : RACSignal
/// Returns a new subject.
+ (instancetype)subject;
// Redeclaration of the RACSubscriber method. Made in order to specify a generic type.
- (void)sendNext:(nullable ValueType)value;
@end
发现RACSubject
继承于RACSignal
,有一个初始化方法subject
和一个发送信号的方法 sendNext
step2:
查看subject
方法
+ (instancetype)subject {
return [[self alloc] init];
}
- (instancetype)init {
self = [super init];
if (self == nil) return nil;
_disposable = [RACCompoundDisposable compoundDisposable];
_subscribers = [[NSMutableArray alloc] initWithCapacity:1];
return self;
}
调用了[[self alloc] init]
方法,并对init
方法进行重写,在init
中对两个属性进行了初始化
- 看下属性的声明
// Contains all current subscribers to the receiver.
//
// This should only be used while synchronized on `self`.
@property (nonatomic, strong, readonly) NSMutableArray *subscribers;
// Contains all of the receiver's subscriptions to other signals.
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
用一个数组保存所有的订阅者,另一个对象用来取消订阅
step3:
查看订阅subscribeNext:
方法,这是父类的方法
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
- 创建订阅者
+ (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;
}
创建一个订阅者,将传进来的参数赋值给订阅者的成员变量,在例子中就是将订阅的block与订阅者关联上。
- subscribe 调用的是
RACSubject
类中的subscribe
- (RACDisposable *)subscribe:(id)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];
}
[disposable addDisposable:[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 obj, NSUInteger index, BOOL *stop) {
return obj == subscriber;
}];
if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
}
}]];
return disposable;
}
将上一步创建的订阅者保存在第一步创建的数组中
step4:
查看sendNext:
方法
- (void)sendNext:(id)value {
[self enumerateSubscribersUsingBlock:^(id subscriber) {
[subscriber sendNext:value];
}];
}
遍历所有的订阅者
- 查看遍历方法
- (void)enumerateSubscribersUsingBlock:(void (^)(id subscriber))block {
NSArray *subscribers;
@synchronized (self.subscribers) {
subscribers = [self.subscribers copy];
}
for (id subscriber in subscribers) {
block(subscriber);
}
}
self.subscribers
是第一步中创建的数组,遍历数组将其中的订阅者对象取出来,调用传进来的block方法。
- 查看遍历回调中的
sendNext
,这是调用的RACSubscriber
的方法
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
从订阅者对象中取出next
变量,即第二步中订阅信号时的block,然后调用这个block方法
。
RACSignal
既然从前面得知RACSubject
继承于RACSignal
,那我们就研究下RACSignal
// 1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
// 3.发送信号
[subscriber sendNext:@"liu"];
//发送完成信号 并取消订阅
[subscriber sendCompleted];
// 4.取消信号,如果信号想要被取消,就必须返回一个RACDisposable
return [RACDisposable disposableWithBlock:^{
NSLog(@"取消订阅");
}];
}];
[signal subscribeNext:^(id x) {
// block的调用时刻:只要信号内部发出数据就会调用这个block
NSLog(@"======%@", x);
}];
运行结果
源码分析
step1:
查看createSignal
方法
+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
//简单看下 RACDynamicSignal
//一个私有的RACSignal子类实现它们的订阅行为
// A private `RACSignal` subclasses that implements its subscription behavior
// using a block.
@interface RACDynamicSignal : RACSignal
+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe;
@end
- 查看
RACDynamicSignal
类中的createSignal
方法
+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
这个方法中主要做了两件事
- 1、创建一个信号量对象
- 2、将外面传进来的block保存在信号量对象的
_didSubscribe
变量中
step2:
查看订阅信号subscribeNext
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
这个方法主要做了两件事
1、创建订阅者
2、执行订阅命令
subscriberWithNext: error: completed:
前面已经讲过,这里就不再讲述查看
subscribe:
方法,是在RACDynamicSignal
类中
- (RACDisposable *)subscribe:(id)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;
}
关键代码在self.didSubscribe(subscriber);
,在创建信号量时将传进来的block
赋值给了self.didSubscribe
,此时调用self.didSubscribe(subscriber);
即调用block并将订阅者对象传进去
问题是
self.didSubscribe(subscriber);
的调用这是在block中,那这个block是在什么时候调用?
- 查看
schedule
方法,是RACSubscriptionScheduler
类的方法
- (RACDisposable *)schedule:(void (^)(void))block {
NSCParameterAssert(block != NULL);
if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
block();
return nil;
}
可以看到传进来的参数block被调用
step3:
sendNext
发送信号
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
从订阅者对象中取出next变量,即第二步中订阅信号时的block,然后调用这个block方法
RACReplaySubject
RACReplaySubject *subject = [RACReplaySubject subject];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribeNext - %@",x);
}];
[subject sendNext:@"liu"];
运行结果
subscribeNext - liu
源码分析
step1:
先看下它的.h文件
保存它发送的值
/// A replay subject saves the values it is sent (up to its defined capacity)
/// and resends those to new subscribers. It will also replay an error or
/// completion.
@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;
@end
RACReplaySubject
是RACSubject
的子类,对外只暴露了一个replaySubjectWithCapacity
方法,这是个初始化方法
step2:
看下replaySubjectWithCapacity
方法实现
+ (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity {
return [(RACReplaySubject *)[self alloc] initWithCapacity:capacity];
}
- (instancetype)init {
return [self initWithCapacity:RACReplaySubjectUnlimitedCapacity];
}
- (instancetype)initWithCapacity:(NSUInteger)capacity {
self = [super init];
_capacity = capacity;
_valuesReceived = (capacity == RACReplaySubjectUnlimitedCapacity ? [NSMutableArray array] : [NSMutableArray arrayWithCapacity:capacity]);
return self;
}
不管是通过自己的初始化方法replaySubjectWithCapacity
,还是通过父类的初始化方法subject
,最终都会调用initWithCapacity
方法,在initWithCapacity
方法里创建了一个数组用来存储发送信号时传递的数据。
step2:
订阅信号subscribeNext
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
第一步创建订阅者与父类是相同的,创建一个订阅者并将block保存在订阅者的成员变量中。
第二步调用的
RACReplaySubject
自己的方法
- (RACDisposable *)subscribe:(id)subscriber {
RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
@synchronized (self) {
for (id value in self.valuesReceived) {
if (compoundDisposable.disposed) return;
[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 {
RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
[compoundDisposable addDisposable:subscriptionDisposable];
}
}
}];
[compoundDisposable addDisposable:schedulingDisposable];
return compoundDisposable;
}
会遍历第一步创建的数组保存的数据,然后发送信号,即订阅信号流程中包含发送信号
。
step3:
发送信号sendNext
,注意这是在RACReplaySubject
中实现
- (void)sendNext:(id)value {
@synchronized (self) {
[self.valuesReceived addObject:value ?: RACTupleNil.tupleNil];
if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
[self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
}
[super sendNext:value];
}
}
会将发送的数据保存在第一步创建的数组中以便订阅信号时使用,最终发送信号还是调用的父类的方法。
问题:
RACReplaySubject
与RACSubject
有什么区别
RACSubject
中代码必须按照创建信号
-->订阅信号
-->发送信号
,这样的先后顺序,否则无效;而在RACReplaySubject
中创建信号
后,订阅信号
与发送信号
顺序无所谓。
所以RACReplaySubject
写成下面这样也是可以的。
RACReplaySubject *subject = [RACReplaySubject subject];
[subject sendNext:@"liu"];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribeNext - %@",x);
}];
RACCommand
- (void)testRACCommand {
/**
* RACCommand使用注意
* 1、RACCommand内部必须返回RACSignal
* 2、executionSignals信号中的信号,一开始获取不到内部信号
* 2.1 使用switchToLatest:获取内部信号
* 2.2 使用execute:获取内部信号
* 3、executing判断是否正在执行
* 3.1 第一次不准确,需要skip:跳过
* 3.2 一定要记得sendCompleted,否则永远不会执行完成
* 4、通过执行execute,执行command的block
*/
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
return [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
[subscriber sendNext:@"发送第1条信号"];
[subscriber sendCompleted];
return nil;
}];
}];
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
}];
[[command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
//NSLog(@"x = %@", x);
if (x.boolValue) {
NSLog(@"x = %@ 正在执行", x);
} else {
NSLog(@"x = %@ 执行完成", x);
}
}];
[command execute:@1];
}
源码分析
step1:
查看RACCommand
类的.h文件
1. executionSignals:需要执行的block成功的时候返回的信号,他是在主线程执行的。
2. executing:信号量 监听RACCommand的状态
3. enabled:当前命令是否enabled,默认是no,他也可以根据enableSignal来设置或者allowsConcurrentExecution设置为NO的时候(command已经开始执行)
4. errors:执行command的时候获取的error都会通过这个信号发送
5. allowsConcurrentExecution:是否允许并发执行command,默认是NO。
6.initWithSignalBlock:(RACSignal * (^)(id input))signalBlock:初始化RACCommand,参数为返回一个信号的block,即block返回的是executionSignals
7.- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock:第一个参数设置当前command是否可用,第二个是执行的block。enableed默认是yes,所以第二个参数也可以为nil。
8.execute:(id)input:调用command,input为executionSignals的订阅者发送的值
step2:
查看初始化方法
- (instancetype)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock {
return [self initWithEnabled:nil signalBlock:signalBlock];
}
- (instancetype)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock {
NSCParameterAssert(signalBlock != nil);
self = [super init];
_addedExecutionSignalsSubject = [RACSubject new];
_allowsConcurrentExecutionSubject = [RACSubject new];
_signalBlock = [signalBlock copy];
_executionSignals = [[[self.addedExecutionSignalsSubject
map:^(RACSignal *signal) {
return [signal catchTo:[RACSignal empty]];
}]
deliverOn:RACScheduler.mainThreadScheduler]
setNameWithFormat:@"%@ -executionSignals", self];
// `errors` needs to be multicasted so that it picks up all
// `activeExecutionSignals` that are added.
//
// In other words, if someone subscribes to `errors` _after_ an execution
// has started, it should still receive any error from that execution.
RACMulticastConnection *errorsConnection = [[[self.addedExecutionSignalsSubject
flattenMap:^(RACSignal *signal) {
return [[signal
ignoreValues]
catch:^(NSError *error) {
return [RACSignal return:error];
}];
}]
deliverOn:RACScheduler.mainThreadScheduler]
publish];
_errors = [errorsConnection.signal setNameWithFormat:@"%@ -errors", self];
[errorsConnection connect];
RACSignal *immediateExecuting = [[[[self.addedExecutionSignalsSubject
flattenMap:^(RACSignal *signal) {
return [[[signal
catchTo:[RACSignal empty]]
then:^{
return [RACSignal return:@-1];
}]
startWith:@1];
}]
scanWithStart:@0 reduce:^(NSNumber *running, NSNumber *next) {
return @(running.integerValue + next.integerValue);
}]
map:^(NSNumber *count) {
return @(count.integerValue > 0);
}]
startWith:@NO];
_executing = [[[[[immediateExecuting
deliverOn:RACScheduler.mainThreadScheduler]
// This is useful before the first value arrives on the main thread.
startWith:@NO]
distinctUntilChanged]
replayLast]
setNameWithFormat:@"%@ -executing", self];
RACSignal *moreExecutionsAllowed = [RACSignal
if:[self.allowsConcurrentExecutionSubject startWith:@NO]
then:[RACSignal return:@YES]
else:[immediateExecuting not]];
if (enabledSignal == nil) {
enabledSignal = [RACSignal return:@YES];
} else {
enabledSignal = [enabledSignal startWith:@YES];
}
_immediateEnabled = [[[[RACSignal
combineLatest:@[ enabledSignal, moreExecutionsAllowed ]]
and]
takeUntil:self.rac_willDeallocSignal]
replayLast];
_enabled = [[[[[self.immediateEnabled
take:1]
concat:[[self.immediateEnabled skip:1] deliverOn:RACScheduler.mainThreadScheduler]]
distinctUntilChanged]
replayLast]
setNameWithFormat:@"%@ -enabled", self];
return self;
}
将传进来的block拷贝到变量_signalBlock
中,以便后面使用。
step3:
查看command.executing subscribeNext:
,订阅信号从而获取RACCommand
的状态
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
点击subscribeNext
进入的是RACSignal
文件,但是查看self
会发现是RACReplaySubject
- 进入
RACReplaySubject
的subscribe
方法
- (RACDisposable *)subscribe:(id)subscriber {
RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
@synchronized (self) {
for (id value in self.valuesReceived) {
if (compoundDisposable.disposed) return;
[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 {
RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
[compoundDisposable addDisposable:subscriptionDisposable];
}
}
}];
[compoundDisposable addDisposable:schedulingDisposable];
return compoundDisposable;
}
step4:
RACCommand
执行命令execute
- (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);
NSCAssert(signal != nil, @"nil signal returned from signal block for value: %@", input);
// We subscribe to the signal on the main thread so that it occurs _after_
// -addActiveExecutionSignal: completes below.
//
// This means that `executing` and `enabled` will send updated values before
// the signal actually starts performing work.
RACMulticastConnection *connection = [[signal
subscribeOn:RACScheduler.mainThreadScheduler]
multicast:[RACReplaySubject subject]];
[self.addedExecutionSignalsSubject sendNext:connection.signal];
[connection connect];
return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, RACDescription(input)];
}
-
self.signalBlock(input)
,self.signalBlock
是第一步中外部传进来的block,这句代码就是执行外面的block
RACTuple
在 CocoaReactive
中,有些信号流传递的信号量是由其他多个信号流传递的信号量组合而成的,而这多个信号量则是封装在一个 RACTuple
实例中进行传递的。