将RACCommands组合成一个共同结果的最佳方法是什么?

时间:2013-11-08 19:44:44

标签: ios objective-c reactive-cocoa

使用ReactiveCocoa 2.0,有没有更好的方法来执行以下操作,而无需实现/取消实现,并且仍然能够从3个信号中的任何一个中捕获错误,而无需重复代码?

有3个登录按钮。每个返回对应于异步“登录”API调用的信号。完成后,它们将返回用户对象,错误和/或完成。

// 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.");
     }];
 }];

1 个答案:

答案 0 :(得分: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);
    }];