Once you’ve sipped from the Reactive Kool-Aid it can become emotionally painful to have to implement callback methods the old-fashioned way when you hit a delegate-style API that doesn’t have a prebuilt Observable
wrapper.
Max Alexander did a great tutorial post on how to implement your own DelegateProxy
for such an API, but unfortunately it won’t work for delegates that that have required methods. A common mistake is to implement the required delegate method in your DelegateProxy
class, forward the call using self._forwardToDelegate
, and then call rx_delegate.observe()
as before. This will result in the fairly misleading message:
Delegate proxy is already implementing `xxx:`, a more performant way of registering might exist.
The right way to implement a DelegateProxy
for a delegate protocol with required methods involves doing the following (using the Google Identity Toolkit here as an example):
- First implement the
DelegateProxy
as per Max’s instructions, i.e.:class RxGIDSignInDelegateProxy: DelegateProxy, GIDSignInDelegate, DelegateProxyType { static func currentDelegateFor(object: AnyObject) -> AnyObject? { let signin = object as! GIDSignIn return signin.delegate } static func setCurrentDelegate(delegate: AnyObject?, toObject object: AnyObject) { let signin = object as! GIDSignIn signin.delegate = delegate as? GIDSignInDelegate } }
- Next declare a 1ocal
PublishSubject
property in your proxy, and publishNext
&Error
events to the subject within the delegate method. You can see we’re also forwarding to the traditional delegate (if one exists), and for completeness’ sake, sendingCompleted
ondeinit
.let signInSubject = PublishSubject<GIDGoogleUser>() func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) { if let u = user { signInSubject.on(.Next(u)) } else if let e = error { signInSubject.on(.Error(e)) } self._forwardToDelegate?.signIn(signIn, didSignInForUser: user, withError: error) } deinit { signInSubject.on(.Completed) }
- At this point, we can implement our
rx_*
extension method on the relevant class.PublishSubject
is a subclass ofObservable
, so we can just return this value directly.extension GIDSignIn { public var rx_delegate: DelegateProxy { return proxyForObject(RxGIDSignInDelegateProxy.self, self) } public var rx_userDidSignIn: Observable<GIDGoogleUser> { let proxy = proxyForObject(RxGIDSignInDelegateProxy.self, self) return proxy.signInSubject } // implement your optional delegate methods with `rx_delegate.observe` }
That’s it! Observe away without sullying your code with delegate callbacks.
Thanks for your, very helpful. I’m having some problem while migrate from Delegate to RxSwift Operator.