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
满足上面三点就算完全的双向绑定
