Reputation: 2165
class A{
func addTarget(target: Any, action: Selector)
}
Let's say I don't have class A source available (framework). How would I extend this class reactively to emit Rx events through an Observable?
I can create a class that just forwards the events through a PublishSubject, but in that case I wouldn't be creating a Reactive extension but doing it through a proxy class.
let a = A()
let del = CustomClassThatAddsItselfAsATarget(a)
del.event.subscribe( ...
instead of
let a = A()
a.rx.event.subscribe( ...
Upvotes: 1
Views: 944
Reputation: 33967
This was a fun exploration. I patterned the below off of how UIControl is set up in RxCocoa.
In answer to your followup questions:
Which object will add itself as a target(addTarget method) to base?
You have to create a class that is designed to do that. I named it ATarget
.
Who retains that object?
You make the object conform to Disposable
and then it will be retained until disposed of.
extension Reactive where Base: A {
var event: Observable<A> {
return Observable.create { [weak a = self.base] observer in
guard let a = a else {
observer.on(.completed)
return Disposables.create()
}
let aTarget = ATarget(a: a, callback: { a in
observer.on(.next(a))
})
return Disposables.create(with: aTarget.dispose)
}
.takeUntil(deallocated)
}
}
class ATarget: NSObject, Disposable {
typealias Callback = (A) -> Void
let selector: Selector = #selector(ATarget.eventHandler)
weak var a: A?
var callback: Callback?
init(a: A, callback: @escaping Callback) {
self.a = a
self.callback = callback
super.init()
a.addTarget(target: self, action: selector)
}
@objc func eventHandler() {
if let callback = self.callback, let a = self.a {
callback(a)
}
}
func dispose() {
self.a?.removeTarget(target: self)
self.callback = nil
}
}
Upvotes: 1
Reputation: 4077
RxCocoa
and most other RxSwift
-based frameworks take the following approach -
public extension Reactive where Base: TheOriginalClass {
See CKRecord+Rx or Bundle+Rx for an example of implementation.
Things get more complicated if you need to provide a proxy delegate, but this is out of scope of this question.
Upvotes: 0