抛出问题
首先来看几个问题吧,我们知道监听UITextField
可以通过如下的方式:
1 | textfield.rx.text |
但是如果我们这样去改变它的值,是订阅不到的。
1 | textfield.text = "这是我修改的值" |
还有UILabel
不是一个可被观察对象,所以下面这么写是会报错的:
1 | label.rx.text |
但是UITextView
既可以被订阅,修改text
也可以被订阅到。
1 | textview.rx.text |
为什么都是UI
控件差别这么大(捂脸
why?
其实这个时候你要思考一下,为什么他们能被观察为什么又不可以?
UITextField
我们前面讲过,它的.allEditingEvents
和.valueChanged
事件会发射值,所以它可以作为被观察对象。
但是textfield.text = "这是我修改的值"
并不会触发上面两种事件,所以你这样修改并没有被订阅到。
UILabel
是继承UIView
不是继承UIControl
所以它不会响应事件,也就不能作为可被观察对象。
UITextView
来看下它是怎么发射值的。
从源码可以看到它是通过NSTextStorageDelegate.textStorage(_:didProcessEditing:range:changeInLength:)
这个delegate
的回调来发射值的。所以可以作为一个被观察者。
当我们textview.text = "这是我修改的值"
这样去修改text
的时候,会触发上面delegate
的回调,所以会被订阅到。
解决?
问题已经找到了,怎么去解决这些问题?
比如我想要
textfield.text = "这是我修改的值"
这样去赋值也会发射事件。
这里我们可以用到双向绑定,把UITextField
的修改和赋值绑定到一个Subject
,同时还可以被订阅。
首先重载<->
操作符,后面我们通过这个操作符去进行双向绑定。
1 | func <-> <Base: UITextInput>(textInput: TextInput<Base>, variable: Variable<String>) -> Disposable { |
使用<->
双向绑定:
1 | let text = Variable("双向绑定") |
那么这样去修改text
就能被订阅到了。
再来扩展一下UILabel
:
1 | extension UILabel { |
观察text
的改变,改变的时候发射值,代码可以这么写了:
1 | textfield.rx.text |
总结
所以现在知道了为什么前面有几种不同的表现了吧。
其实很多UIControl
的子类控件,都可以通过这种双向绑定的方式,以便我们修改它的值时能够被订阅者订阅到。
代码见github: