0

我正在使用 ReactiveCocoa 和 Overcoat/Mantle/AFNetworking 来获取数据并从 RESTful API 验证用户。

这是登录视图控制器中管理登录按钮和凭据文本字段的代码:

@weakify(self);
self.loginButton.rac_command =
[[RACCommand alloc] initWithEnabled:validCredentials
                        signalBlock:^RACSignal *(id input) {
                            @strongify(self);
                            return [[PFUserManager sharedManager] logInUser:self.usernameTextField.text
                                                            password:self.passwordTextField.text];
                        }];

// Handle errors for the login command
[self.loginButton.rac_command.errors subscribeNext:^(NSError *error) {
    // Present the error message
    [PFErrorAlertFactory showOVCError:error];
}];

// Take care of the signal from the request
[[self.loginButton.rac_command.executionSignals flatten] subscribeNext:^(NSNumber *success) {
    @strongify(self);
    [self clearTextFields];
    [self.flowController controllerForMainScreen]; // Transition to "logged in state"
} error:^(NSError *error) {
    @strongify(self);
    [self clearTextFields];
}];

我在单例 UserManager 类上有这个方法:

- (RACSignal *)logInUser:(NSString *)username password:(NSString *)password {
    // Return a cold signal that sends next and complete when user is authenticated and error if authentication failed.

    PFAPIClient *client = [[PFAPIClient alloc] initWithUsername:username password:password];

    @weakify(self);
    RACSignal *loginSignal = [[client rac_POST:kAuthenticationResourcePath parameters:nil] doNext:^(OVCResponse *response) {
        @strongify(self);
        self.currentUser = response.result;
        NSError *error;
        [SSKeychain setPassword:password forService:kKeychainServiceKey account:self.currentUser.username error:&error];
        if (error) {
            [PFErrorAlertFactory showLocalizedDescriptionOfError:error];
        }
    }];

    return loginSignal;
}

这一切都很好,使用这个信号作为按钮的 RACCommand 信号。我在登录视图控制器中处理下一个、错误和完成的事件,它工作正常。

正如您在 UserManager 代码中看到的,在 doNext 块中,如果 Keychain 方法返回一个错误,我将显示错误。我有点不确定这个错误处理是否属于这个类。

它确实有效,错误显示为 UIAlertView,但是这个 UserManager 类真的应该负责显示错误吗?

来自 rac_POST 信号的错误由登录视图控制器处理,我也想在这里处理来自 Keychain 方法的错误。是否可以从 doNext 块内向 rac_POST 信号的订阅者发送错误?我错过了一个指向订阅者的指针......同样,如果 Keychain 方法中发生错误,信号仍然会发送 next 并完成,并且就调用视图控制器所知,登录是成功的。这显然不是它应该工作的方式。

有没有其他首选的方式来处理这整个情况?我知道 doNext 块中的副作用不是首选,但在这种情况下,我看不到其他解决方案,因为我希望 UserManager 拥有此方法并能够设置自己的 currentUser。我是否应该将其包装在一个新信号中并显式发送 next、complete 和 error ?

问候,延斯

4

1 回答 1

1

您可以创建SSKeychain类别:

@interface SSKeychain (RACExtension)
- (RACSignal*)rac_setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;
@end

@implementation SSKeychain (RACExtension)

- (RACSignal*)rac_setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account 
{
    [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSError *error;
        BOOL result = [SSKeychain setPassword:password forService:service account:account error:&error];
        if (result) {
            [subscriber sendNext:@(result)];
            [subscriber sendCompleted];
        } else {
            [subscriber sendError:error];
        }
    }];
}

@end

然后使用它UserManager

- (RACSignal *)logInUser:(NSString *)username password:(NSString *)password 
{
    PFAPIClient *client = [[PFAPIClient alloc] initWithUsername:username password:password];

    @weakify(self);
    return [[[client rac_POST:kAuthenticationResourcePath parameters:nil]
             flattenMap:^RACStream *(OVCResponse *response){
                 @strongify(self)
                 return [[SSKeychain rac_setPassword:password forService:kKeychainServiceKey account:self.currentUser.username]
                         mapReplace:response];
             }]
             doNext:^(OVCResponse *response){
                 @strongify(self)
                 self.currentUser = response.result;
             }]
}
于 2015-06-11T06:39:15.123 回答