RxSwift中的双向绑定 [英] Two way binding in RxSwift

查看:871
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆