[英]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.