[英]Two way binding with custom signal with Reactive Cocoa not working as expected
[英]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。
以下是模擬器的快照:
我只想在所有三個字段都有效時啟用“注冊”按鈕。 我還想在鍵盤上禁用“開始”按鈕,直到驗證成功。
好的,有兩件事:
您可以使用RACSignal
的and
幫助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.