2016-05-28 196 views
5

我讀了RxSwift示例代碼中的雙向綁定操作符。雙向綁定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) 
} 

property改變,它會通知變量,並設置變量的值,而該變量的值時,它會通知物業。我認爲這將導致無限循環......

回答

5

謝謝你提出的問題,我花了一些時間各地ControlProperty實施挖掘(注意:我添加了一個.debug()呼叫跟蹤控制財產所產生的價值)。

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) 
     } 
    } 
} 

我的測試設置如下,我已經刪除了所有的意見在這裏的定位,使其更短:

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) 
} 

我們的結果。首先我們嘗試點擊按鈕,該按鈕應將變量設置爲true。這會觸發ControlProperty上的on(event: Event<E>)並將開關值設置爲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`) 

接下來讓我們觸發交換機。所以我們可以看到,控制生成了一個事件,其結果爲UIControlEventValueChanged,它通過ControlProperty上的_values傳遞,然後將其值分配給Variable值,如上例所示。但是沒有迴路,因爲更新到Variable值不會在交換機上觸發控制事件。

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`) 

因此,一個簡單的解釋是:

  • 從控制值一次發射某種UIControlEvent被觸發
  • 當值直接分配給控件屬性,控制不會觸發更改事件,所以沒有循環。

希望它能幫助,對不起,有點亂的解釋 - 我已經通過實驗發現了這件事)

10

我相信你可以只使用bindTo。以下是ControlProperty <-> VariableVariable <-> Variable實現:的ControlProperty <-> Variable(如UITextFieldUITextView

infix operator <-> { precedence 130 associativity left } 

func <-><T: Comparable>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable { 
    let variableToProperty = variable.asObservable() 
     .distinctUntilChanged() 
     .bindTo(property) 

    let propertyToVariable = property 
     .distinctUntilChanged() 
     .bindTo(variable) 

    return StableCompositeDisposable.create(variableToProperty, propertyToVariable) 
} 

func <-><T: Comparable>(left: Variable<T>, right: Variable<T>) -> Disposable { 
    let leftToRight = left.asObservable() 
     .distinctUntilChanged() 
     .bindTo(right) 

    let rightToLeft = right.asObservable() 
     .distinctUntilChanged() 
     .bindTo(left) 

    return StableCompositeDisposable.create(leftToRight, rightToLeft) 
} 

實例是具有可變<->可變的RxSwiftPlayer project

// Example of Variable <-> Variable 

let disposeBag = DisposeBag() 
let var1 = Variable(1) 
let var2 = Variable(2) 

(var1 <-> var2).addDisposableTo(disposeBag) 

var1.value = 10 
print(var2.value) // 10 

var2.value = 20 
print(var1.value) // 20 
+0

尼斯例子。然而,我不能讓它與變量<[URL]>這樣的數組一起工作。有什麼建議麼? – mkkrolik