[英]Combining multiple signal not working using Reactive Cocoa
I am following this tutorial: http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1 . 我正在学习本教程: http : //www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1 。 It is working for username and password field. 它适用于用户名和密码字段。
I am trying to create sign up form which contains three fields: email, password, confirmPassword. 我正在尝试创建包含三个字段的注册表单:email,password,confirmPassword。
I have validated email address (working perfectly) I have validated password like this: 我已经验证了电子邮件地址(工作正常)我已经验证了这样的密码:
password should be at least 6 characters and both password and confirmPassword must be same. 密码至少应为6个字符,密码和confirmPassword必须相同。
Here is my code: 这是我的代码:
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];
}];
Here, if I take only emailValid's value, it is sending 1 when valid. 在这里,如果我只接受emailValid的值,则在有效时发送1。 But if I include all three values, it always returns 0 even if all are valid. 但是如果我包含所有三个值,即使所有值都有效,它也总是返回0。
Here are snap shots of the simulator: 以下是模拟器的快照:
I just wanted to enable "Sign up" button when all three fields are valid. 我只想在所有三个字段都有效时启用“注册”按钮。 I also want disable "Go" button on the keyboard till validation success. 我还想在键盘上禁用“开始”按钮,直到验证成功。
Okay, two things: 好的,有两件事:
You can use the and
helper of RACSignal
to make that signal reduction a little cleaner: 您可以使用RACSignal
的and
帮助RACSignal
信号减少更清洁:
RACSignal *signUpActiveSignal = [[RACSignal combineLatest:@[validEmailSignal,
validPasswordSignal,
validConfirmPasswordSignal]] and];
You can also use the RAC
macro to bind the enabled
property (the only reason that the example code is using subscribeNext
instead of RAC
is that CGColorRef
isn't of type id
): 您还可以使用RAC
宏来绑定enabled
属性(示例代码使用subscribeNext
而不是RAC
的唯一原因是CGColorRef
不是id
类型):
RAC(self.signUpButton, enabled) = signUpActiveSignal;
Now onto the reason this isn't working. 现在说这不起作用的原因。 Let's look at the calculations for the password fields: 我们来看看密码字段的计算:
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);
}];
Every time passwordTextField
's text changes, it compares it to confirmPasswordTextField
. 每次passwordTextField
的文本发生更改时,都会将其与confirmPasswordTextField
进行比较。 But it only checks that they're the same when passwordTextField
changes, not when confirmPasswordTextField
changes. 但它只会在passwordTextField
更改时检查它们是否相同, 而不是在confirmPasswordTextField
更改时。 So let's imagine the following scenario, ignoring (for now) the length requirement: 所以让我们想象下面的场景,忽略(现在)长度要求:
------------------- 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
-------------
Aha! 啊哈! So we need to recalculate when either of them changes. 因此,我们需要在其中任何一个发生变化时重新计算。 And, really, that should be a separate signal from the lengths: 而且,实际上,这应该是与长度分开的信号:
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);
}];
Then we can put it all together: 然后我们可以把它们放在一起:
RACSignal *signUpActiveSignal = [[RACSignal combineLatest:@[validEmailSignal,
isPasswordLongEnough,
passwordsMatch]] and];
Which is great, because that's sort of how we think of it: "You can sign in when the email address is valid, the password you entered is long enough, and the password confirm field matches the password." 这很好,因为我们就是这样想的:“当电子邮件地址有效时,您可以登录,输入的密码足够长,密码确认字段与密码匹配。” Declarative! 声明!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.