繁体   English   中英

使用Reactive Cocoa组合多个信号不起作用

[英]Combining multiple signal not working using Reactive Cocoa

我正在学习本教程: http//www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1 它适用于用户名和密码字段。

我正在尝试创建包含三个字段的注册表单:email,password,confirmPassword。

我已经验证了电子邮件地址(工作正常)我已经验证了这样的密码:

密码至少应为6个字符,密码和confirmPassword必须相同。

这是我的代码:

RACSignal *validEmailSignal =
[emailTextField.rac_textSignal
 map:^id(NSString *text) {
     return @([text isValidEmailAddress]);
 }];

RACSignal *validPasswordSignal =
[passwordTextField.rac_textSignal
 map:^id(NSString *text) {
     return @([text isEqualToString:self.confirmPasswordTextField.text] && text.length >5);
 }];

RACSignal *validConfirmPasswordSignal =
[confirmPasswordTextField.rac_textSignal
 map:^id(NSString *text) {
     return @([text isEqualToString:self.passwordTextField.text] && text.length >5 );
 }];

[[validEmailSignal
  map:^id(NSNumber *emailValid) {
      return [emailValid boolValue] ? [UIColor greenColor] : [UIColor redColor];
  }]
 subscribeNext:^(UIColor *color) {
     emailTextField.layer.borderColor=[color CGColor];
     emailTextField.layer.borderWidth= 1.0f;

 }];

[[validPasswordSignal
  map:^id(NSNumber *passwordValid) {
      return [passwordValid boolValue] ? [UIColor greenColor] : [UIColor redColor];
  }]
 subscribeNext:^(UIColor *color) {
     passwordTextField.layer.borderColor=[color CGColor];
     passwordTextField.layer.borderWidth= 1.0f;
     confirmPasswordTextField.layer.borderColor=[color CGColor];
     confirmPasswordTextField.layer.borderWidth= 1.0f;
 }];

[[validConfirmPasswordSignal
  map:^id(NSNumber *passwordValid) {
      return [passwordValid boolValue] ? [UIColor greenColor] : [UIColor redColor];
  }]
 subscribeNext:^(UIColor *color) {
     passwordTextField.layer.borderColor=[color CGColor];
     passwordTextField.layer.borderWidth= 1.0f;
     confirmPasswordTextField.layer.borderColor=[color CGColor];
     confirmPasswordTextField.layer.borderWidth= 1.0f;
 }];


RACSignal *signUpActiveSignal =
[RACSignal combineLatest:@[validEmailSignal, validPasswordSignal, validConfirmPasswordSignal]
                  reduce:^id(NSNumber *emailValid, NSNumber *passwordValid, NSNumber *confirmPasswordValid) {
                      return @([emailValid boolValue] && [passwordValid boolValue] && [confirmPasswordValid boolValue]);
                  }];


[signUpActiveSignal subscribeNext:^(NSNumber *signupActive) {

    NSLog(@"sign up button enabled : %hhd", [signupActive boolValue]);
    _signUpButton.enabled = [signupActive boolValue];
}];

在这里,如果我只接受emailValid的值,则在有效时发送1。 但是如果我包含所有三个值,即使所有值都有效,它也总是返回0。

以下是模拟器的快照:

在此输入图像描述在此输入图像描述

我只想在所有三个字段都有效时启用“注册”按钮。 我还想在键盘上禁用“开始”按钮,直到验证成功。

好的,有两件事:

您可以使用RACSignaland帮助RACSignal信号减少更清洁:

RACSignal *signUpActiveSignal = [[RACSignal combineLatest:@[validEmailSignal,
                                                            validPasswordSignal,
                                                            validConfirmPasswordSignal]] and];

您还可以使用RAC宏来绑定enabled属性(示例代码使用subscribeNext而不是RAC的唯一原因是CGColorRef不是id类型):

RAC(self.signUpButton, enabled) = signUpActiveSignal;

现在说这不起作用的原因。 我们来看看密码字段的计算:

RACSignal *validPasswordSignal = [passwordTextField.rac_textSignal map:^id(NSString *text) {
    return @([text isEqualToString:self.confirmPasswordTextField.text] && text.length > 5);
}];

RACSignal *validConfirmPasswordSignal = [confirmPasswordTextField.rac_textSignal map:^id(NSString *text) {
    return @([text isEqualToString:self.passwordTextField.text] && text.length > 5);
}];

每次passwordTextField的文本发生更改时,都会将其与confirmPasswordTextField进行比较。 但它只会在passwordTextField更改时检查它们是否相同, 而不是confirmPasswordTextField更改时。 所以让我们想象下面的场景,忽略(现在)长度要求:

------------------- initial state -------------------

           -------------
password: |             |   passwordValid: YES
           -------------

           -------------
 confirm: |             |   confirmValid: YES
           -------------

-------------- user types in a password --------------

           -------------
password: | asdf        |   passwordValid: NO
           -------------

           -------------
 confirm: |             |   confirmValid: YES (this will only recalculate when the confirm field changes, not when the password field changes)
           -------------


------- user types in the password confirmation -------

           -------------
password: | asdf        |   passwordValid: NO (this didn't recalculate because the contents of the password field didn't change)
           -------------

           -------------
 confirm: | asdf        |   confirmValid: YES
           -------------

啊哈! 因此,我们需要在其中任何一个发生变化时重新计算。 而且,实际上,这应该是与长度分开的信号:

RACSignal *passwordsMatch = [RACSignal combineLatest:@[passwordTextField.rac_textSignal,
                                                       confirmPasswordTextField.rac_textSignal]
                                              reduce:(NSString *password, NSString *confirm) {
                                                  return @([password isEqualToString:confirm]);
                                              }];

RACSignal *isPasswordLongEnough = [passwordTextField.rac_textSignal map:^(NSString *text) {
    return @(text.length >= 6);
}];

然后我们可以把它们放在一起:

RACSignal *signUpActiveSignal = [[RACSignal combineLatest:@[validEmailSignal,
                                                            isPasswordLongEnough,
                                                            passwordsMatch]] and];

这很好,因为我们就是这样想的:“当电子邮件地址有效时,您可以登录,输入的密码足够长,密码确认字段与密码匹配。” 声明!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM