RxSwift/RxCocoa/OSX/NSControl+Rx.swift

95 lines
2.8 KiB
Swift

//
// NSControl+Rx.swift
// RxCocoa
//
// Created by Krunoslav Zaher on 5/31/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
import Foundation
import Cocoa
#if !RX_NO_MODULE
import RxSwift
#endif
var rx_value_key: UInt8 = 0
var rx_control_events_key: UInt8 = 0
extension NSControl {
/**
Reactive wrapper for control event.
*/
public var rx_controlEvents: ControlEvent<Void> {
MainScheduler.ensureExecutingOnScheduler()
let source = rx_lazyInstanceObservable(&rx_control_events_key) { () -> Observable<Void> in
Observable.create { [weak self] observer in
MainScheduler.ensureExecutingOnScheduler()
guard let control = self else {
observer.on(.Completed)
return NopDisposable.instance
}
let observer = ControlTarget(control: control) { control in
observer.on(.Next())
}
return observer
}.takeUntil(self.rx_deallocated)
}
return ControlEvent(events: source)
}
/**
Helper to make sure that `Observable` returned from `createCachedObservable` is only created once.
This is important because on OSX there is only one `target` and `action` properties on `NSControl`.
*/
func rx_lazyInstanceObservable<T: AnyObject>(key: UnsafePointer<Void>, createCachedObservable: () -> T) -> T {
if let value = objc_getAssociatedObject(self, key) {
return value as! T
}
let observable = createCachedObservable()
objc_setAssociatedObject(self, key, observable, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return observable
}
func rx_value<T>(getter getter: () -> T, setter: T -> Void) -> ControlProperty<T> {
MainScheduler.ensureExecutingOnScheduler()
let source = rx_lazyInstanceObservable(&rx_value_key) { () -> Observable<T> in
return Observable.create { [weak self] observer in
guard let control = self else {
observer.on(.Completed)
return NopDisposable.instance
}
observer.on(.Next(getter()))
let observer = ControlTarget(control: control) { control in
observer.on(.Next(getter()))
}
return observer
}.takeUntil(self.rx_deallocated)
}
return ControlProperty(values: source, valueSink: AnyObserver { event in
switch event {
case .Next(let value):
setter(value)
case .Error(let error):
bindingErrorToInterface(error)
case .Completed:
break
}
})
}
}