ReactiveCocoa Combine Latest with Button press and Text Field Delegate Signal

724 views Asked by At

I've created a signal to wrap the UITextField Delegate Method textFieldShouldReturn:.

- (RACSignal *)textFieldReturnPressed
{
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[self rac_signalForSelector:@selector(textFieldShouldReturn:)
                       fromProtocol:@protocol(UITextFieldDelegate)]
        subscribeNext:^(RACTuple *tuple) {
            [subscriber sendNext:tuple.first];
        }];

        return nil;
    }];
}

In viewDidLoad, I'm attempting to subscribe to the combination of this signal and a button press. In effect, I'd like a user to be able to tap a button and do some things (login), or press return on the keyboard and do the same things (login).

I've created the following signal to combine the two signals:

RACSignal *loginSignal = [RACSignal
                          combineLatest:@[[loginButton
                                                     rac_signalForControlEvents:UIControlEventTouchUpInside],
                                                    [self textFieldReturnPressed]]];

I then subscribe to this event like so:

[loginSignal
    subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];

When I press the return key on the keyboard, the log above doesn't print (although I have verified sendNext is called from the signal). However, when I trigger the login button signal, the log prints ie. combineLatest passes through the signal.

I've experimented with adding startWith:nil to the loginButton signal, because, as I've found in other posts/Github issues, CombineLatest requires each signal to have been sent at least once, but my stream executes immediately.

I'm sure I could somehow filter at that point to prevent the stream from executing, but that feels a bit hacky. Any recommendations?

1

There are 1 answers

2
Charles Maria On

The reason why combineLatest isn't give the desired effect is that it needs every signal passed to send at least one next event for subscribers to start receiving next events.

To achieve the effect you want, i.e. two signals with each passing a next event irrespective of the other's state, you should merge: the signals.

Example:

RACSignal *loginSignal = [[loginButton 
                          rac_signalForControlEvents:UIControlEventTouchUpInside] 
                         merge:[self textFieldReturnPressed]];