RAC双向绑定UITextField的正确姿势
一句话概括文章内容
UITextField
使用RACChannelTo
的情况
- 问题描述
直接使用RACChannelTo
实现
UITextField
的双向绑定是有隐患的
- 问题展示
// 使用RACChannelTo双向绑定
RACChannelTo(self, string) = RACChannelTo(self.textField, text);
// 结果1:通过键盘给self.textField.text赋值的情况
// self.textField.text 改变 self.string 不改变
// self.string 改变 self.textField.text 改变
// 结果2:通过代码给self.textField.text赋值的情况
eg: `self.textField.text = @"123";` // 通过代码赋值
// self.textField.text 改变 self.string 改变
// self.string 改变 self.textField.text 改变
-
问题结论
使用
RACChannelTo(self.textField, text)
,
当通过code改变self.textField. text
的值的时候
才会把这个值发送出去
UITextField
使用rac_newTextChannel
的情况
- 问题描述
直接使用rac_newTextChannel
实现
UITextField
的双向绑定是有隐患的
- 问题展示
// 使用rac_newTextChannel双向绑定
RACChannelTo(self, string) = self.textField.rac_newTextChannel;
// 结果1:通过键盘给self.textField.text赋值的情况
// self.textField.text 改变 self.string 改变
// self.string 改变 self.textField.text 改变
// 结果2:通过代码给self.textField.text赋值的情况
eg: `self.textField.text = @"123";` // 通过代码赋值
// self.textField.text 改变 self.string 不改变
// self.string 改变 self.textField.text 改变
-
问题结论
使用
self.textField.rac_newTextChannel
,
当通过键盘改变self.textField. text
的值的时候
才会把这个值发送出去
问题总结
无论是使用RACChannelTo
还是rac_newTextChannel
self.string
的值改变的时候,
self.textField.text
都会跟着改变
也就是说
self.string
-> self.textField.text
的这个单向通道是没问题的
问题就在
无论是通过键盘或者code赋值来改变textField.text
的值的时候,我们都要让绑定的string
对应的改变,这才是我们要的双向绑定
RACChannelTo |
rac_newTextChannel |
---|---|
当通过code改变self.textField.text 的值的时候才会把这个值发送出去 |
当通过键盘改变self.textField. text 的值的时候才会把这个值发送出去 |
解决方案
- 错误做法 --
rac_textSignal
作祟导致
RACChannelTo(self, string) = self.textField.rac_newTextChannel;
此方式双向绑定存在问题:通过code改变self.textField.text
的值时,不会发送值出去,导致绑定string
失败
因为我们针对这个痛点来解决
RACChannelTo(self, string) = self.textField.rac_newTextChannel;
@weakify(self);
// 当 self.textField.text改变的时候,会回调这个block,然后再给string赋值,实现双向绑定
[self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
@strongify(self);
self.string = x;
}];
结果: 当self.textField.text = @"12312";
code赋值的时候,self.textField.rac_textSignal
不会触发回调
原因 是rac_textSignal
这个signal是监听UIControlEventAllEditingEvents
的,所以对setter
方式不会触发signal(setter
方式就是 属性A = @"123"
)
- (RACSignal *)rac_textSignal {
@weakify(self);
return [[[[[RACSignal
defer:^{
@strongify(self);
return [RACSignal return:self];
}]
concat:[self rac_signalForControlEvents:UIControlEventAllEditingEvents]]
map:^(UITextField *x) {
return x.text;
}]
takeUntil:self.rac_willDeallocSignal]
setNameWithFormat:@"%@ -rac_textSignal", self.rac_description];
}
rac_textSignal
的实现,从中主要看到
concat:[self rac_signalForControlEvents:UIControlEventAllEditingEvents]]
// concat: 连接信号,第一个信号必须发送完成,第二个信号才会被激活
// 也就是说,必须触发UIControlEventAllEditingEvents才会触发rac_textSignal,所以用setter的方式赋值就gg了
- 正确做法
RACChannelTo(self, string) = RACChannelTo(self.textField, text);
此方式双向绑定存在问题:通过键盘改变self.textField.text
的值时,不会发送值出去,导致绑定string
失败
因为我们针对这个痛点来解决
RACChannelTo(self, string) = RACChannelTo(self.textField, text);
@weakify(self);
[self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
@strongify(self);
self.string = x;
}];
简化代码
RACChannelTo(self, string) = RACChannelTo(self.textField, text);
[self.textField.rac_textSignal subscribe:RACChannelTo(self, string)];
结语
UITextView
的情况及处理跟UITextField
一样
对于整篇文章双向绑定的分析,主要围绕三个点
-
string
->textField.text
- 键盘改变
textField.text
->string
- code赋值
textField.text
->string
满足上面三点就算完全的双向绑定
网友评论