RxSwift中的双向绑定 [英] Two way binding in RxSwift
问题描述
我读了RxSwift示例代码中的双向绑定操作符。
func< - > < T>(属性:ControlProperty< T>,变量:Variable< T>) - > Disposable {
let bindToUIDisposable = variable.asObservable()
.bindTo(property)
let bindToVariable = property
.subscribe(onNext:{n in
variable.value = n
},onCompleted:{
bindToUIDisposable.dispose()
})
返回StableCompositeDisposable.create(bindToUIDisposable,bindToVariable)
}
当属性
改变时,它会通知变量,设置变量的值,而变量的值被设置,它会通知该属性。我认为这会导致无尽的循环......
感谢提出这个问题,我花了一些时间仔细研究 ControlProperty
实现(注意我添加了一个 .debug()
调用来跟踪为控件属性生成的值) / p>
公共结构ControlProperty< PropertyType> :ControlPropertyType {
public typealias E = PropertyType
let _values:Observable< PropertyType>
让_valueSink:AnyObserver< PropertyType>
public init< V:ObservableType,S:ObserverType where E == VE,E == S.E>(values:V,valueSink:S){
_values = values.debug (Control property values)。subscribeOn(ConcurrentMainScheduler.instance)
_valueSink = valueSink.asObserver()
}
public func on(event:Event< E>){
switch event {
case .Error(let error):
bindingErrorToInterface(error)
case .Next:
_valueSink.on(event)
case .Completed:
_valueSink.on(event)
}
}
}
我的测试设置如下,我已经删除了所有位置缩小的视图:
import UIKit
import RxSwift
import RxCocoa
class ViewController:UIViewController {
let variable = Variable< Bool>(false);
let bag = DisposeBag();
重写func loadView(){
super.loadView()
let aSwitch = UISwitch();
view.addSubview(aSwitch)
(aSwitch.rx_value - - > variable).addDisposableTo(bag);
let button = UIButton();
button.rx_tap.subscribeNext {[weak self] in
self?.variable.value = true;
} .addDisposableTo(bag)
view.addSubview(button);
}
}
中缀运算符< - > {
}
func< - > < T>(属性:ControlProperty< T>,变量:Variable< T>) - >一次性{
let bindToUIDisposable = variable.asObservable()。debug(绑定中的变量值)
.bindTo(property)
let bindToVariable = property
。 debug(绑定中的属性值)
.subscribe(onNext:{n in
variable.value = n
},onCompleted:{
bindToUIDisposable.dispose()
$)
返回StableCompositeDisposable.create(bindToUIDisposable,bindToVariable)
}
现在看结果。首先我们尝试点击按钮,该按钮应将变量设置为 true
。这将在ControlProperty上触发 on(event:Event< E>)
,并将开关值设置为 true
。
2016-05-28 12:24:33.229:绑定中的变量值 - >事件下一步(true)
//值流程
赋值给变量 - >
变量发出事件 - >
ControlProperty收到事件 - >
赋值给底层控制属性的值(例如``on`UISwitch`)
下一步让我们触发交换机本身。正如我们所看到的那样,控件通过ControlProperty上的 _values
传递的 UIControlEventValueChanged
产生了一个事件,然后将其值分配给 Variable
值,如上例所示。但没有循环,因为更新变量
值不会触发交换机上的控制事件。
2016-05-28 12:29:01.957:控制属性值 - > Event Next(false)
2016-05-28 12:29:01.957:绑定中的属性值 - > Event Next(false)
2016-05-28 12:29:01.958:绑定中的变量值 - > Event Next(false)
//数值流
触发控制状态(例如`UISwitch`) - >
ControlProperty发出事件 - >分配给变量的
值 - >
变量发出事件 - >
ControlProperty收到事件 - >
赋给底层控制属性的值(例如``on`UISwitch`)
一个简单的解释是:
- 一旦某种类型的
UIControlEvent
被触发 - 当一个值直接赋值给control属性时,控件不会触发change事件,所以没有循环。
希望它有帮助,抱歉有点混乱的解释 - 我已经通过实验发现了它)
I read the two way binding operator in sample code of RxSwift.
func <-> <T>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable {
let bindToUIDisposable = variable.asObservable()
.bindTo(property)
let bindToVariable = property
.subscribe(onNext: { n in
variable.value = n
}, onCompleted: {
bindToUIDisposable.dispose()
})
return StableCompositeDisposable.create(bindToUIDisposable, bindToVariable)
}
When property
changed, it will notify variable, and set the variable's value, while the variable's value is set, it will notify the property. I think it will lead to endless loop...
Thanks for raising the question, I spent some time digging around the ControlProperty
implementation (note I've added a .debug()
call to trace the values generated for control property).
public struct ControlProperty<PropertyType> : ControlPropertyType {
public typealias E = PropertyType
let _values: Observable<PropertyType>
let _valueSink: AnyObserver<PropertyType>
public init<V: ObservableType, S: ObserverType where E == V.E, E == S.E>(values: V, valueSink: S) {
_values = values.debug("Control property values").subscribeOn(ConcurrentMainScheduler.instance)
_valueSink = valueSink.asObserver()
}
public func on(event: Event<E>) {
switch event {
case .Error(let error):
bindingErrorToInterface(error)
case .Next:
_valueSink.on(event)
case .Completed:
_valueSink.on(event)
}
}
}
My test setup was as following, I've removed all views positioning here to make it shorter:
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let variable = Variable<Bool>(false);
let bag = DisposeBag();
override func loadView() {
super.loadView()
let aSwitch = UISwitch();
view.addSubview(aSwitch)
(aSwitch.rx_value <-> variable).addDisposableTo(bag);
let button = UIButton();
button.rx_tap.subscribeNext { [weak self] in
self?.variable.value = true;
}.addDisposableTo(bag)
view.addSubview(button);
}
}
infix operator <-> {
}
func <-> <T>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable{
let bindToUIDisposable = variable.asObservable().debug("Variable values in bind")
.bindTo(property)
let bindToVariable = property
.debug("Property values in bind")
.subscribe(onNext: { n in
variable.value = n
}, onCompleted: {
bindToUIDisposable.dispose()
})
return StableCompositeDisposable.create(bindToUIDisposable, bindToVariable)
}
Now to the results. First we try tapping the button, which should set the variable to true
. This triggers on(event: Event<E>)
on ControlProperty and sets the switch value to true
.
2016-05-28 12:24:33.229: Variable values in bind -> Event Next(true)
// value flow
value assigned to Variable ->
Variable emits event ->
ControlProperty receives event ->
value assigned to underlying control property (e.g. `on` for `UISwitch`)
Next lets trigger the switch itself. So as we can see, the control generated an event as a result of UIControlEventValueChanged
which was passed through _values
on ControlProperty, and then its value got assigned to Variable
value as in example above. But there's no loop, since update to the Variable
value doesn't trigger a control event on the switch.
2016-05-28 12:29:01.957: Control property values -> Event Next(false)
2016-05-28 12:29:01.957: Property values in bind -> Event Next(false)
2016-05-28 12:29:01.958: Variable values in bind -> Event Next(false)
// value flow
trigger the state of control (e.g. `UISwitch`) ->
ControlProperty emits event ->
value assigned to Variable ->
Variable emits event ->
ControlProperty receives event ->
value assigned to underlying control property (e.g. `on` for `UISwitch`)
So a simple explanation would be:
- a value from a control is emitted once some kind of
UIControlEvent
is triggered - when a value is assigned directly to the control property, the control doesn't trigger a change event so there's no loop.
Hope it helps, sorry for a bit messy explanation - I've found it out by experiment)
这篇关于RxSwift中的双向绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!