Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Question about combining signals in ReactiveCocoa
@interface LoginViewController ()
@property (strong, nonatomic) RACSubject *textFieldReturnPressed;
@property (strong, nonatomic) UITextField *usernameTextField;
@property (strong, nonatomic) UITextField *passwordTextField;
@end
@implementation LoginViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_textFieldReturnPressed = [RACSubject subject];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self addSubview:self.usernameTextField];
[self addSubview:self.passwordTextField];
RACSignal *validUsername = [self.usernameTextField.rac_textSignal map:^(NSString *username) {
return @(username.length > 0 && [username isAValidEmail]);
}];
RACSignal *validPassword = [self.passwordTextField.rac_textSignal map:^(NSString *password) {
return @(password.length > 0);
}];
[[self.textFieldReturnPressed combineLatestWith:validUsername] subscribeNext:^(RACTuple *values) {
RACTupleUnpack(UITextField *textField, NSNumber *validity) = values;
if (validity.boolValue && [textField isEqual:self.usernameTextField]) {
[self.passwordTextField becomeFirstResponder];
}
}];
[[self.textFieldReturnPressed combineLatestWith:validPassword] subscribeNext:^(RACTuple *values) {
RACTupleUnpack(UITextField *textField, NSNumber *validity) = values;
if (validity.boolValue && [textField isEqual:self.passwordTextField]) {
// start log in process
}
}];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.textFieldReturnPressed sendNext:textField];
return YES;
}
// other implementation details skipped...
@end
@milancermak

This comment has been minimized.

Copy link
Owner Author

@milancermak milancermak commented Jun 13, 2013

I have this view controller.

I want to combine a signal that checks the validity of the input (e.g. validUsername or validPassword) with the textFieldReturnPressed which is sent in textFieldShouldReturn:.

The problem with this code above is that combineLatestWith: is triggered too often (on every change of a text field). What I need is a method similar to combineLatestWith: but without this call to sendNext(), i.e. one that would produce a new signal only when the receiver changes.

Alternatively, is there a better way to implement this behavior?

@joshaber

This comment has been minimized.

Copy link

@joshaber joshaber commented Jun 13, 2013

So you only want your login process to start when the form is valid, correct?

One way to think about it is that you want to sequence the check for validity after the return.

You could do something like:

[[[[[self.textFieldReturnPressed 
    filter:^ BOOL (UITextField *field) {
        @strongify(self);
        return field == self.passwordTextField;
    }] 
    sequenceMany:^{
        return validPassword;
    }] 
    filter:^(NSNumber *valid) {
        return valid.boolValue;
    }] 
    subscribeNext:^(id _) {
        // do some login stuff
    }];

But you probably want to check the whole validity of the form, not just the password:

RACSignal *formValid = [RACSignal 
    combineLatest:@[ validPassword, validUsername ] 
    reduce:^(NSNumber *validPassword, NSNumber *validUsername) {
        return validPassword.boolValue && validUsername.boolValue; 
    }];

Hopefully that helps!

@milancermak

This comment has been minimized.

Copy link
Owner Author

@milancermak milancermak commented Jun 14, 2013

Right now, I'm just trying to execute the code on line #34 - basically switch the focus from username text field to password text field when the user hits return (and if the input is correct, as determined by the validUsername signal).

The problem with my code is that because it's using combineWithLatest:, the beginFirstResponder is executed too often. I've tried to adapt the piece of code you suggested to this task, but it has the same effect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment