使用反应可可登录按钮仅触发一次



这是我的基本场景:

我正在制作一个简单的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都不会被触发。

就像错误信号丢失了什么的。

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

所以请帮忙,谢谢。

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

您可以使用

RACCommand,它将为您处理很多问题:

@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/@strongifyself的引用,以避免内存泄漏。

最新更新