Tag: RACCommand

  • Using RACCommand and creating custom RACSignals in Objective C

    To bind some action to the button click one can use just a custom RACSignal. But then you have to add three more things in every case:
    1. Disable button, while action is performing;
    2. Show, that action is in progress;
    3. Disable button, if input is incorrect and button should not be able to be tapped.

    Instead, if you use RACCommand, you get all these things in a box.

    Let’s say, we want to bind RACCommand verifyPhoneCommand to a button. We can create a command in a lazy property in a ViewModel:

    - (RACCommand *)verifyPhoneCommand
    {
        if (! _verifyPhoneCommand) {
            _verifyPhoneCommand = [[RACCommand alloc] initWithEnabled:self.phoneValidSignal
                                                          signalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
                                                              return [self verifyPhone];
                                                          }];
        }
        return _verifyPhoneCommand;
    }
    

    Here phoneValidSignal is this signal, that is formed by observing a phone variable:

    - (RACSignal *)phoneValidSignal
    {
        if (!_phoneValidSignal) {
            _phoneValidSignal = [RACObserve(self, phone) map:^id(NSString *phone) {
                return @(phone.length > 0);
            }];
        }
        return _phoneValidSignal;
    }
    

    We pass a RACSignal verifyPhone to the RACCommand to do a job:

    - (RACSignal *)verifyPhone
    {
        return [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
    
            [[PhoneManager sharedManager]
             requestVerifyPhone:self.phone
             success:^{
    
                 [subscriber sendNext:@(YES)];
                 [subscriber sendCompleted];
                 
             } failure:^(NSError *error) {
                 
                 [subscriber sendError:error];
                 
             }];
            
            return nil;
        }];
    }
    

    This is how we bind a RACCommand to a button:

    self.smsRequestButton.rac_command = self.viewModel.verifyPhoneCommand;
    

    To track execution of a RACCommand and show an activity indicator we can use executing property:

    [self.viewModel.verifyPhoneCommand.executing subscribeNext:^(NSNumber*  _Nullable x) {
            if (x.boolValue) {
                [self.spinnerView startAnimating];
            }
            else {
                [self.spinnerView stopAnimating];
            }
        }];
    

    If errors happen during RACCommand execution we can process those errors:

    [self.viewModel.verifyPhoneCommand.errors subscribeNext:^(NSError * _Nullable error) {
            [ErrorUtil showError:error from:self onRepeat:^{
                
            }];
        }];