美文网首页iOS开发随记
RACCommand在开发中踩过坑

RACCommand在开发中踩过坑

作者: 危险地带_浅笑 | 来源:发表于2017-10-28 11:28 被阅读588次

    RACCommand基本用法

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

       RACCommand * command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            NSLog(@"%@",input);
            //2,执行这个block
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> 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;
    

    打印结果


    image.png

    RACCommand在MVVM中的实战

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

    viewModel中的代码:

        -(RACCommand *)command{
        if (!_command) {
            _command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
                return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> 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;
    }
    

    打印结果为


    image.png

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

    -(RACCommand *)command{
        if (!_command) {
            _command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
                return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> 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;
    }
    

    打印结果:


    image.png

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

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

    相关文章

      网友评论

        本文标题:RACCommand在开发中踩过坑

        本文链接:https://www.haomeiwen.com/subject/ycsdpxtx.html