【问题标题】:ReactiveCocoa - observing isFirstResponder property and UITextField with clearsOnBeginEditing set to YESReactiveCocoa - 观察 isFirstResponder 属性和 UITextField,clearsOnBeginEditing 设置为 YES
【发布时间】:2014-02-06 23:37:07
【问题描述】:

我是 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]

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

【问题讨论】:

    标签: validation uitextfield reactive-cocoa


    【解决方案1】:

    不幸的是,-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]];
    }
    

    【讨论】:

    • 根据设计,在 text 属性上仅观察到文本更改。之前已经讨论过此类拉取请求,但无意这样做。查看我的问题以获取更多详细信息:github.com/ReactiveCocoa/ReactiveCocoa/issues/516
    • 这不起作用,字段在成为第一响应者后被清除,并且在成为第一响应者后自动清除字段不会发送文本更改的信号。首先会通知我编辑已开始,然后(稍后)字段将被清除。
    • 行不通?你试过了吗?我试过了,它似乎工作。出于某种原因,看起来“编辑开始时清除”选项会导致文本值在UIControlEventEditingDidBegin 事件触发之前更新。如果您记录这些值,您会看到该字段为空。
    • @allprog 我不确定这个问题是否相同。您说的是在程序更新而不是控制事件之后接收-rac_textSignal。我在这里建议的只是考虑一个额外的控制事件。这样做的重点是在需要时正确获取更新的值 - 我认为“编辑开始时清除”与用户及其键盘驱动的实际文本更改相当。就好像用户用退格键删除了整个字段。
    • 大家好,仅供参考,以备不时之需,它已合并到 2.0 主版本中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多