簡體   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