2

Using ReactiveCocoa 2.0, is there a better way to do the following, without having to materialize/dematerialize and still being able to capture errors from any of the 3 signals, without duplicating code?

There are 3 login buttons. Each returns a signal corresponding to an asynchronous "login" API call. Once those finish, they return user objects, errors, and/or completion.

// Login signals
_loginButton.rac_command = [[RACCommand alloc] initWithEnabled:loginValid signalBlock:^RACSignal *(id input) {
    return [[API doLogin:_usernameField.text password:_passwordField.text] materialize];
}];
_fbLoginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    return [[API doFacebookLogin] materialize];
}];
_twLoginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    return [[API doTwitterLogin] materialize];
}];

// Login response from any of the 3 signals
[[RACSignal
  merge:@[_loginButton.rac_command.executionSignals,
          _fbLoginButton.rac_command.executionSignals,
          _twLoginButton.rac_command.executionSignals]]
 subscribeNext:^(RACSignal *loginSignal) {
     RACSignal * s = [loginSignal dematerialize];
     [s subscribeNext:^(User *x) {
        NSLog(@"user: %@", x);
     } error:^(NSError *error) {
        NSLog(@"error: %@", error);
     } completed:^{
        NSLog(@"Completed.");
     }];
 }];
4

1 回答 1

8

由于错误会自动转移到errors信号上,因此您通常不必自己处理具体化或任何其他事情。事实上,这种(潜在的)复杂性是错误特殊行为的最初动机。

只需合并错误信号并在一个地方处理它们:

[[RACSignal
    merge:@[
        _loginButton.rac_command.errors,
        _fbLoginButton.rac_command.errors,
        _twLoginButton.rac_command.errors,
    ]]
    subscribeNext:^(NSError *error) {
        NSLog(@"error: %@", error);
    }];

作为旁注,您还可以使用-flatten- 而不是内部订阅 - 来简化登录响应的处理:

[[[RACSignal
    merge:@[
        _loginButton.rac_command.executionSignals,
        _fbLoginButton.rac_command.executionSignals,
        _twLoginButton.rac_command.executionSignals,
    ]]
    // Flattens the signal of `User` signals by one level. The result is
    // one signal of `User`s.
    //
    // This avoids any need for an inner subscription.
    flatten]
    subscribeNext:^(User *x) {
        // This means that a login request completed as well, so there's no need
        // for a separate `completed` block.
        NSLog(@"user: %@", x);
    }];
于 2013-11-11T08:32:18.123 回答