ReactiveCocoa - 观察isFirstResponder属性和UITextField,并将clearsOnBeginEditing设置为YES

时间:2014-02-06 23:37:07

标签: validation uitextfield reactive-cocoa

我是ReactiveCocoa的新手,但我认为这是降低代码复杂性的非常好的优秀技术。我刚刚开始体验这个框架,目前并不是一切都清楚,所以请原谅我,如果我的问题可以用一些明显的方式解决。

在我的应用程序中,我有登录视图控制器,简单形式包含两个文本字段(用户名和密码)和一个按钮。如果两个文本字段中的任何一个为空,我希望禁用该按钮。所以,我写了这段代码:

RAC(self.loginButton, enabled) = 
[RACSignal combineLatest:@[self.userTextField.rac_textSignal,
                           self.passwordTextField.rac_textSignal]
                  reduce:^(NSString *username,
                           NSString *password) {
                      BOOL valid = (username.length > 0 && password.length > 0);
                      return @(valid);
                  }];

这很简单,而且很有效。问题是我的一个文本字段(密码字段)将secureTextEntryclearsOnBeginEditing属性设置为YES。我将尝试解释我在使用此配置时遇到的不需要的行为:

我们假设用户名和密码字段都不为空。在这种情况下,按钮已启用。当用户点击密码字段时,它成为第一响应者(出现键盘并且用户可以输入他的密码),但由于该字段的clearsOnBeginEditing被设置为YES,因此从文本字段中清除先前输入的密码。这是密码字段现在为空的方式。问题是没有发送信号,所以尽管密码字段为空,按钮仍保持启用状态。

我解决这个问题的第一个想法(更像是解决方法)就是在观察文本更改旁边的密码字段上观察isFirstResponder属性。当密码字段成为第一响应者时,将调用检查是否应启用按钮的块。我不知道这个解决方案是否有效,因为我不知道如何使用ReactiveCocoa实现它。我一直在寻找为isFirstResponder属性更改创建信号,但没有运气。为了解决这个问题,这可能不是最好的方法,但此时我没有想到任何事情。

然后,问题是:如何使用ReactiveCocoa观察isFirstResponder属性?

更一般的问题:当clearsOnBeginEditing设置为YES时,如何观察文本字段的文本更改?

更新

我发现我可以为UIControlEventEditingDidBegin事件创建信号,该信号可以替代观察isFirstResponder属性更改:

[self.passwordTextField rac_signalForControlEvents:UIControlEventEditingDidBegin]

不幸的是,这并没有解决问题。现在我知道该字段在它成为第一响应者后被清除,并且在它成为第一响应者之后自动清除字段不发送文本更改的信号。当执行验证块时,它仍然认为密码字段不为空,并且尽管密码字段被清除且它是空的,该按钮仍保持启用状态。

1 个答案:

答案 0 :(得分:3)

不幸的是,-rac_textSignal只会监听UIControlEventEditingChanged。如果添加了UIControlEventEditingDidBegin,您就会全部设置。

我想你可以将其修补并提交拉取请求吗?

- (RACSignal *)rac_textSignal {
    @weakify(self);
    return [[[[[RACSignal
        defer:^{
            @strongify(self);
            return [RACSignal return:self];
        }]
        concat:[self rac_signalForControlEvents:UIControlEventEditingChanged|UIControlEventEditingDidBegin]]
        map:^(UITextField *x) {
            return x.text;
        }]
        takeUntil:self.rac_willDeallocSignal]
        setNameWithFormat:@"%@ -rac_textSignal", [self rac_description]];
}