在ReactiveSwift中,<~运算符实现了数据源(Source)到数据目标(Target)之间的绑定关系,实现了数据源的值发生变化时,数据目标同时得到更新,实际应用一般是在UI控件的值随与之绑定的ViewModel的值同步更新。
例如一个UILabel,绑定到ViewModel中的labelValue: MutableProperty
let label = UILabel()
label.reactive.text <~ viewModel.labelValue
之后,一旦ViewModel的labelValue值发生变化,则同步到视图中的label进行显示,一次绑定,终生享用,无需人工干预。
那么,这种绑定关系如何实现的,下面进行源码分析
从 <~的源码开始分析入手:
<~函数在BindingTargetProvider协议中声明,调用这个方法是由表达式左边的对象作为Self发起的
BindingTarget <~ BindingSource |
e.g. label.reactive.text <~ viewModel.labelValue |
首先我们分析BindingTarget
BindingTarget主要包含一个(Value) -> Void 的action闭包,在构造的时候传入action逃逸闭包
通过让UILabel遵守ReactiveExtensionProvider协议,并扩展Reactive where Base: UILabel方式,为UILabel增加Reactive扩展属性
makeBindingTarget { 1 } 实现了BindingTarget的self.base.text = value的赋值动作,也是在<~运算符中的provider.bindingTarget.action动作,就是这里的赋值动作,至此,BindingTarget这端的动作及协议实现完成,下面来看BindingSource这边需要完成的协议。
我们来实现一个简单的AA类,让这个类同时符合BindingTarget和BindingSource两个协议的要求
AA类的实现点:
在构造时,自身保存一对(signal, observer)
扩展AA类遵守BindingSource协议,声明producer计算属性,在SignalProducer的startHandler中,调用自身的observer发送值消息,并将SignalProducer构造的observer添加至自身signal中保存
扩展AA类遵守BindingTarget协议,声明tareget计算属性,返回makeBindingTarget { $0.name = $1 },完成赋值动作,这里多讲一点的就是,makeBindingTarget是对BindingTarget的二次封装,在BindingTarget构造中,action是(Value) -> Void类型,这里的makeBindingTarget传参是(Base, Value) -> Void类型,展开makeBindingTarget方法后,可以看到它是怎么进行二次封装的,添加了Base属性在其中。
-
声明changeValue(value: String)方法,在赋值过程中,调用一次自身的observer发送值消息,这里的changeValue动作类似MutableProperty对值类型的封装过程,并这里作了简化便于理解原理,在MutableProperty的赋值过程中,是调用了内部的Box对存储的值进行了一次封装,并涉及到原子操作。
调用AA.changeValue后,一次调用AA自身的observer.send -> AA.producer.observer.send -> provider.bindingTarget.action 最终完成赋值动作