RACCommand在开发中踩过坑

RACCommand基本用法

RACCommandReactiveCocoa框架里面一个非常重要的类。先看一下他的基本用法

   RACCommand * command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        NSLog(@"%@",input);
        //2,执行这个block
        return [RACSignal createSignal:^RACDisposable *(id subscriber) {
            //3,发送信号
            [subscriber sendNext:input];
            //一定要sendCompleted  不然command.executing无法接收到信号停止的动作
            [subscriber sendCompleted];
            return nil;
        }];
    }];

    //获取最新信号的值
    [command.executionSignals.switchToLatest subscribeNext:^(id x) {
        //4,打印信号中的值
        NSLog(@"executionSignals:%@",x);
    }];

    [command.executing subscribeNext:^(NSNumber * x) {
        //信号的状态
        NSLog(@"executing:%@",x);
    }];

    //1, 执行命令 实际上就是调用之前的哪个block
    [command execute:@"123"];
    _command = command;

打印结果


RACCommand在开发中踩过坑_第1张图片
image.png

RACCommand在MVVM中的实战

RACCommand小试之后,相信有童鞋也和我一样,立马想用在自己的MVVM的项目中了。废话不多说直接上代码:

viewModel中的代码:

    -(RACCommand *)command{
    if (!_command) {
        _command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            return [RACSignal createSignal:^RACDisposable *(id subscriber) {
                /**
                 * 此处做网络请求。。。
                 */
                //请求完成之后这里将结果结果发送出去
                [subscriber sendNext:@"这个是发送的信号"];
                [subscriber sendCompleted];
                return nil;
            }];
        }];
    }
    return _command;
}

ViewController中的代码

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.viewModel.command execute:nil];
    
    [self.viewModel.command.executionSignals.switchToLatest subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    [[self.viewModel.command.executing skip:1] subscribeNext:^(id x) {
        NSLog(@"executing:%@",x);
    }];
}

-(ViewModel *)viewModel{
    if (!_viewModel) {
        _viewModel = [[ViewModel alloc] init];
    }
    return _viewModel;
}

打印结果为


RACCommand在开发中踩过坑_第2张图片
image.png

相信有经验的同学从代码一眼就看眼看出其中的问题,但是我当时对RACCommand不特别熟悉的时候,没有直接看出原因。我当时想是不是我信号有错,所以我直接把viewModel中代码改成如下:

-(RACCommand *)command{
    if (!_command) {
        _command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            return [RACSignal createSignal:^RACDisposable *(id subscriber) {
                /**
                 * 此处做网络请求。。。
                 */
                //请求完成之后这里将结果结果发送出去
                [subscriber sendNext:@"这个是发送的信号"];
                [subscriber sendCompleted];
                return nil;
            }];
        }];
        
        [_command.executionSignals.switchToLatest subscribeNext:^(id x) {
            NSLog(@"viewModel中订阅信号:%@",x);
        }];
    }
    return _command;
}

打印结果:


image.png

咦,这个我就很奇怪了,为什么viewModel里面可以订阅到信号的值,难道是姿势不对?很疑惑。

没办法了,只能重新分析一边执行过程,[self.viewModel.command execute:nil];当我执行这句,实际上首先是进到viewModel里面的get方法,初始化command完成之后,直接执行命令。在此时我在viewModel中初始化command时候订阅了信号

[_command.executionSignals.switchToLatest subscribeNext:^(id x) {
     NSLog(@"viewModel中订阅信号:%@",x);
}];

而我在VC中订阅信号实在执行完命令的之后才进行信号订阅,这难道是传说中的冷信号在作怪吗?查看源码,找到executionSignals初始化方法

_executionSignals = [[[newActiveExecutionSignals
        map:^(RACSignal *signal) {
        return [signal catchTo:[RACSignal empty]];
}]deliverOn:RACScheduler.mainThreadScheduler]setNameWithFormat:@"%@ -executionSignals", self];

正如所料,executionSignals的确是个冷信号呀,冷信号的特点是一定是先订阅才能收到值,于是我将VC中的代码改成

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //switchToLatest最新信号的值
    [self.viewModel.command.executionSignals.switchToLatest subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

    //skip:忽略第一次刚刚创建信号的时候,信号是非激活状态,所以第一次对于我们的场景是无效的
    [[self.viewModel.command.executing skip:1] subscribeNext:^(NSNumber * x) {
        if (x.boolValue) {
            NSLog(@"显示菊花...");
        }else{
            NSLog(@"隐藏菊花...");
        }
    }];
    [self.viewModel.command execute:nil];

}

-(ViewModel *)viewModel{
    if (!_viewModel) {
        _viewModel = [[ViewModel alloc] init];
    }
    return _viewModel;
}

打印结果:


RACCommand在开发中踩过坑_第3张图片
image.png

唉,费了我好久时间终于完美解决。

相关文章推荐:
RACCommand底层实现分析
细说ReactiveCocoa的冷信号与热信号

你可能感兴趣的:(RACCommand在开发中踩过坑)