使用Reactivecocoa登录按钮只触发一次

时间:2016-03-15 07:31:22

标签: ios objective-c reactive-programming reactive-cocoa

这是我的基本情景:

我正在创建一个简单的login框架,因此我有两个text field,一个用于用户名,另一个用于密码,当然还有登录button

现在我将它们与RACSignal绑定在一起:

RACSignal *validPasswordSignal = [passwordTextField.rac_textSignal map:^id(NSString *text)
{
    return @([self isPasswordValid:text]);
}];

RACSignal *validUsernameSignal = [usernameTextField.rac_textSignal map:^id(NSString *text)
{
    return @([self isUsernameValid:text]);
}];

并将两个信号(用户名和密码)合并为一个:

RACSignal *submitActiveSignal = [RACSignal combineLatest:@[validpasswordSignal, validUsernameSignal] reduce:^id(NSNumber *validPW, NSNumber *validUN)
{
    return @(validPW.boolValue && validUN.boolValue);
}];

当然我需要一种方法来向服务器提交用户名和密码的信号,所以我这样做:

-(RACSignal *)submitSignal
{
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber)
    {
        [[[RequestClass alloc] init] requestWithUsername:_usernameTextField.text.trim password:_passwordTextField.text.trim completionHandler:^(MyResult *results, NSURLResponse *response, NSError *error)
        {
            if (!error)
            {
                if (results.code == 0)
                {
                    [subscriber sendNext:@(YES)];
                    [subscriber sendCompleted];
                }
                else
                {
                    NSError *invalidError = [NSError errorWithDomain:MyErrorDomain code:MyErrorInvalidSigniture userInfo:@{@"NSLocalizedDescription": results.message}];
                    [subscriber sendError:invalidError];
                }
            }
            else
            {
                [subscriber sendError:error];
            }
        }];
        return nil;
    }];
}

然后我需要让我的登录按钮捕获来自订阅者sendNextsendError的信号,所以我这样做:

//subscribeNext
[[[[_submitButton rac_signalForControlEvents:UIControlEventTouchUpInside]
doNext:^(id x)
{
    _submitButton.enabled = NO;
}]
flattenMap:^RACStream *(id value)
{
    return [self submitSignal];
}]
subscribeNext:^(NSNumber *signal)
{
    _submitButton.enabled = YES;
    BOOL success = signal.boolValue;
    if (success)
    {
        [self successCallback];
    }
    else
    {
        //do sth
    }
}];

//subscribeError
[[[[_submitButton rac_signalForControlEvents:UIControlEventTouchUpInside]
doNext:^(id x)
{
    _submitButton.enabled = NO;
}]
flattenMap:^RACStream *(id value)
{
    return [self submitSignal];
}]
subscribeError:^(NSError *error)
{
    [self failureCallbackWithError:error];
}];

以上是我为登录程序编写的reactivecocoa代码。当传递和用户名正确时,信号将转到sendNext的响应块:subscribeNext, 但问题是,当凭据不正确,服务器返回错误时,sendErrorsubscribeError都不会被触发。

它就像错误信号丢失了一样。

我不确定我是否使用正确的reactivecocoa方法来处理成功信号和错误信号。

所以请帮助,谢谢。

如果我不清楚我的问题,也请告诉我。

1 个答案:

答案 0 :(得分:0)

您可以使用@weakify(self) RACCommand *submitCommand = [[RACCommand alloc] initWithEnabled:submitActiveSignal signalBlock:^RACSignal *(id input) { @strongify(self) return [[self submitSignal] doCompleted:^{ @strongify(self) [self successCallback]; }]; }]; _submitButton.rac_command = submitCommand; ,它将为您解决很多问题:

submitActiveSignal

通过提供initWithEnabled:作为RACCommand参数,将根据该信号发出的值自动启用/禁用该按钮。

对于错误处理,errors有一个特殊的errors信号,用于发送命令中发生的每个错误。您可以订阅[[submitCommand.errors takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSError *error) { @strongify(self) [self failureCallbackWithError:error]; }]; 信号来处理从命令内部返回的信号所导致的所有错误:

@weakify

不要忘记@strongify / self在信号内部引用Ctrl+\, Ctrl+S以避免内存泄漏。