RACCommand: NSObject

RACCommand 继承自NSObject 用于管理RACSignal信号

RACCommand使用示例

RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            NSInteger integer = [input integerValue];
            for (NSInteger i = 0; i < integer; i++) {
                [subscriber sendNext:@(i)];
            }
            [subscriber sendCompleted];
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"信号销毁了");
            }];
        }];
    }];
    
    [[command.executionSignals switchToLatest] subscribeNext:^(id  _Nullable x) {
        NSLog(@"收到消息---%@",x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"error了");
    } completed:^{
        NSLog(@"completed了");
    }];
    
    [command execute:@1];
    [RACScheduler.mainThreadScheduler afterDelay:0.1
                                        schedule:^{
                                            [command execute:@2];
                                        }];
    [RACScheduler.mainThreadScheduler afterDelay:0.2
                                        schedule:^{
                                            [command execute:@3];
                                        }];
                                        
                            
    //log结果
    收到消息---0
    信号销毁了
    收到消息---0
    收到消息---1
    信号销毁了
    收到消息---0
    收到消息---1
    收到消息---2
    信号销毁了
    completed了
  1. 通过switchToLatest方法来获取信号中的信号
  2. 因为默认情况下RACCommand是不支持并发操作的,需要在上次命令发送完成后,再发送下次信号
@property (nonatomic, strong, readonly) RACSignal<RACSignal<ValueType> *> *executionSignals;

通过以上示例可以看出整个流程中,传入一个block,这个block通过传入值生成对应的signal, 而command属性executionSignals即为这些信号的信号

通过 execute方法 出入值

RACCommand

Command内部 是由几个很重要的信号组成的

初始化

初始化方法需要传入signalBlock, 该block通过input传入值 生成一个RACSignal
在初始化方法中初始化了重要的信号

 RACCommand initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal<id> * (^)(id input))signalBlock {
    _addedExecutionSignalsSubject = [RACSubject new];
    _allowsConcurrentExecutionSubject = [RACSubject new];
    _signalBlock = [signalBlock copy];
    _executionSignals =...
    _errors = ...
    _executing = ...
    _immediateEnabled = ...
    _enabled = ...
 }

addedExecutionSignalsSubject

addedExecutionSignalsSubject即为包含信号的信号 当传入值时通过signalblock生成的signal即包含在改信号中

addedExecutionSignalsSubject信号在execute:执行时,对信号进行订阅和发送

- (RACSignal *)execute:(id)input { 
    BOOL enabled = [[self.immediateEnabled first] boolValue];
    if (!enabled) {
        return [RACSignal error:error];
    }
    RACSignal *signal = self.signalBlock(input);
    //订阅信号
    RACMulticastConnection *connection = [[signal
        subscribeOn:RACScheduler.mainThreadScheduler]
        multicast:[RACReplaySubject subject]];
    //发送信号
    [self.addedExecutionSignalsSubject sendNext:connection.signal];
    [connection connect];
    return connection.signal;
}

immediateExecuting && _executing 表示当前有操作执行的信号

immediateExecuting的逻辑是:
1. catchTo捕获addedExecutionSignalsSubject信号中的error信号,转换为empty
2. flattenMap:将每个信号的开始和结束时间点转为1和-1信号(start为1 then为-1
3. scanWithStart:@0 reduce: 将上一步得到的1和-1进行叠加得到0 或者 非0
1. map:将0/非0 转为 NO/YES 表示当前是否有信号正在处理

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];

将immediateExecuting 信号进行优化 表示当前是否有任务执行

_executing = [[[[immediateExecuting
        deliverOn:RACScheduler.mainThreadScheduler]
        // This is useful before the first value arrives on the main thread.
        startWith:@NO]
        distinctUntilChanged]
        replayLast]

moreExecutionsAllowed 表示是否允许更多信号执行

简单来看就是 当不允许并发时(默认不允许并发),[immediateExecuting not]

RACSignal *moreExecutionsAllowed = [RACSignal
        if:[self.allowsConcurrentExecutionSubject startWith:@NO]
        then:[RACSignal return:@YES]
        else:[immediateExecuting not]];

executionSignals

 @property (nonatomic, strong, readonly) RACSignal<RACSignal<ValueType> *> *executionSignals;

executionSignals是一个包含信号的信号
executionSignals 只是简单的将self.addedExecutionSignalsSubject信号中的所有错误信号NSError转换为了empty信号

_executionSignals = [[self.addedExecutionSignalsSubject
        map:^(RACSignal *signal) {
            return [signal catchTo:[RACSignal empty]];
        }]
        deliverOn:RACScheduler.mainThreadScheduler]

_enabled 信号 表示当前命令是否可以被再次执行

RACSignal *enabledSignal = [RACSignal return:@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]