Skip to content

Commit 33d0083

Browse files
fpilletkzaher
authored andcommitted
Fixed issue with NSControl.rx.value multiple observers
When multiple observers want to look at NSControl.rx.value, only one would get updates because the returned observable wasn't shared(). This is examplified by the new test added to NSButton This also solves the issue of observers with varying types
1 parent cfa0242 commit 33d0083

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

RxCocoa/macOS/NSControl+Rx.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ extension Reactive where Base: NSControl {
3636
}
3737

3838
return observer
39-
}.takeUntil(self.deallocated)
39+
}
40+
.takeUntil(self.deallocated)
41+
.share()
4042
}
41-
43+
4244
return ControlEvent(events: source)
4345
}
4446

@@ -47,25 +49,27 @@ extension Reactive where Base: NSControl {
4749
static func value<C: AnyObject, T>(_ control: C, getter: @escaping (C) -> T, setter: @escaping (C, T) -> Void) -> ControlProperty<T> {
4850
MainScheduler.ensureExecutingOnScheduler()
4951

50-
let source = (control as! NSObject).rx.lazyInstanceObservable(&rx_value_key) { () -> Observable<T> in
51-
return Observable.create { [weak weakControl = control] (observer: AnyObserver<T>) in
52+
let source = (control as! NSObject).rx.lazyInstanceObservable(&rx_value_key) { () -> Observable<Void> in
53+
return Observable.create { [weak weakControl = control] (observer: AnyObserver<Void>) in
5254
guard let control = weakControl else {
5355
observer.on(.completed)
5456
return Disposables.create()
5557
}
5658

57-
observer.on(.next(getter(control)))
59+
observer.on(.next(()))
5860

5961
let observer = ControlTarget(control: control as! NSControl) { _ in
60-
if let control = weakControl {
61-
observer.on(.next(getter(control)))
62+
if weakControl != nil {
63+
observer.on(.next(()))
6264
}
6365
}
64-
66+
6567
return observer
6668
}
67-
.takeUntil((control as! NSObject).rx.deallocated)
68-
}
69+
.takeUntil((control as! NSObject).rx.deallocated)
70+
.share(replay: 1, scope: .forever)
71+
}
72+
.map { [unowned control] _ in getter(control) }
6973

7074
let bindingObserver = UIBindingObserver(UIElement: control, binding: setter)
7175

Tests/RxCocoaTests/NSButton+RxTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,23 @@ extension NSButtonTests {
3939

4040
XCTAssertEqual(button.state, NSControl.StateValue.off)
4141
}
42+
43+
func testButton_multipleObservers() {
44+
let button = NSButton(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
45+
var value1: NSControl.StateValue? = nil
46+
var value2: NSControl.StateValue? = nil
47+
48+
_ = Observable.just(NSControl.StateValue.off).bind(to: button.rx.state)
49+
_ = button.rx.state.subscribe(onNext: { value1 = $0 })
50+
_ = button.rx.state.subscribe(onNext: { value2 = $0 })
51+
_ = Observable.just(NSControl.StateValue.on).bind(to: button.rx.state)
52+
53+
if let target = button.target, let action = button.action {
54+
_ = target.perform(action, with: button)
55+
}
56+
57+
XCTAssertEqual(button.state, NSControl.StateValue.on)
58+
XCTAssertEqual(value1, NSControl.StateValue.on)
59+
XCTAssertEqual(value2, NSControl.StateValue.on)
60+
}
4261
}

0 commit comments

Comments
 (0)