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:
1 2 3 4 5 6 7 8 9 10 |
- (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:
1 2 3 4 5 6 7 8 9 |
- (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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
- (RACSignal *)verifyPhone { return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _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:
1 |
self.smsRequestButton.rac_command = self.viewModel.verifyPhoneCommand; |
To track execution of a RACCommand and show an activity indicator we can use executing property:
1 2 3 4 5 6 7 8 |
[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:
1 2 3 4 5 |
[self.viewModel.verifyPhoneCommand.errors subscribeNext:^(NSError * _Nullable error) { [ErrorUtil showError:error from:self onRepeat:^{ }]; }]; |