Rxswift: DelegateProxy and GIDSignIn (Google sign in) rx extension

Created on 7 Jun 2018  路  9Comments  路  Source: ReactiveX/RxSwift

Short description of the issue:

I am getting "Type 'GIDSignIn' does not conform to protocol 'HasDelegate'" compile time error while trying to add GIDSignIn rx extension.

Expected outcome:

Not to get compile time "Type 'GIDSignIn' does not conform to protocol 'HasDelegate'" error.

What actually happens:

Compile time error.

Self contained code example that reproduces the issue:

extension GIDSignIn: HasDelegate {
    public typealias Delegate = GIDSignInDelegate
}

open class RxGIDSignInDelegateProxy: DelegateProxy<GIDSignIn, GIDSignInDelegate>, DelegateProxyType, GIDSignInDelegate {
    public weak private(set) var gidSignIn: GIDSignIn?

    public init(gidSignIn: ParentObject) {
        self.gidSignIn = gidSignIn
        super.init(parentObject: gidSignIn, delegateProxy: RxGIDSignInDelegateProxy.self)
    }

    public static func registerKnownImplementations() {
        self.register { RxGIDSignInDelegateProxy(gidSignIn: $0) }
    }

    open class func currentDelegate(for object: ParentObject) -> GIDSignInDelegate? {
        return object.delegate
    }

    open class func setCurrentDelegate(_ delegate: GIDSignInDelegate?, to object: ParentObject) {
        object.delegate = delegate
    }

    public func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
        self._forwardToDelegate?.sign(signIn, didSignInFor: user, withError: error)
    }

    public func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
        self._forwardToDelegate?.sign(signIn, didDisconnectWith: user, withError: error)
    }
}

extension Reactive where Base: GIDSignIn {
    public var delegate: DelegateProxy<GIDSignIn, GIDSignInDelegate> {
        return RxGIDSignInDelegateProxy.proxy(for: base)
    }

    public var sign: Observable<Void> {
        return delegate
            .methodInvoked(#selector(GIDSignInDelegate.sign(_:didSignInFor:withError:)))
            .map {_ in}
    }

    public var signOut: Observable<Void> {
        return delegate
            .methodInvoked(#selector(GIDSignInDelegate.sign(_:didDisconnectWith:withError:)))
            .map {_ in}
    }
}

screen shot 2018-06-07 at 15 50 52

Most helpful comment

Hey @VinayakDeshpande11,

Here is my implementation. Works without warnings.

Cheers,
Ivan

import RxSwift
import RxCocoa

open class RxGIDSignInDelegateProxy: DelegateProxy<GIDSignIn, GIDSignInDelegate>, DelegateProxyType, GIDSignInDelegate {
    public weak private(set) var gidSignIn: GIDSignIn?
    var signInSubject = PublishSubject<GIDGoogleUser>()
    var disconnectSubject = PublishSubject<GIDGoogleUser>()

    public init(gidSignIn: ParentObject) {
        self.gidSignIn = gidSignIn
        super.init(parentObject: gidSignIn, delegateProxy: RxGIDSignInDelegateProxy.self)
    }

    public static func registerKnownImplementations() {
        self.register { RxGIDSignInDelegateProxy(gidSignIn: $0) }
    }

    open class func currentDelegate(for object: ParentObject) -> GIDSignInDelegate? {
        return object.delegate
    }

    open class func setCurrentDelegate(_ delegate: GIDSignInDelegate?, to object: ParentObject) {
        object.delegate = delegate
    }

    public func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
        if let u = user {
            self.signInSubject.on(.next(u))
        } else if let e = error {
            self.signInSubject.on(.error(e))
        }
        self._forwardToDelegate?.sign(signIn, didSignInFor: user, withError: error)
    }

    public func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
        if let u = user {
            self.disconnectSubject.on(.next(u))
        } else if let e = error {
            self.disconnectSubject.on(.error(e))
        }
        self._forwardToDelegate?.sign(signIn, didDisconnectWith: user, withError: error)
    }

    deinit {
        self.signInSubject.on(.completed)
        self.disconnectSubject.on(.completed)
    }
}

extension Reactive where Base: GIDSignIn {
    public var delegate: DelegateProxy<GIDSignIn, GIDSignInDelegate> {
        return self.gidSignInDelegate
    }

    private var signIn: Single<GIDGoogleUser> {
        let proxy = self.gidSignInDelegate
        proxy.signInSubject = PublishSubject<GIDGoogleUser>()
        return proxy.signInSubject
            .asObservable()
            .do(onSubscribed: {
                proxy.gidSignIn?.signIn()
            })
            .take(1)
            .asSingle()
    }

    private var signOut: Single<GIDGoogleUser> {
        let proxy = self.gidSignInDelegate
        proxy.signInSubject = PublishSubject<GIDGoogleUser>()
        return proxy.disconnectSubject
            .asObservable()
            .do(onSubscribed: {
                proxy.gidSignIn?.signOut()
            })
            .take(1)
            .asSingle()
    }

    private var gidSignInDelegate: RxGIDSignInDelegateProxy {
        return RxGIDSignInDelegateProxy.proxy(for: base)
    }
}

All 9 comments

Hi @IvanKalaica ,

I would assume that you would like your code to compile, but why do you think that we have a bug in this repo and that we can do something about this?

It's not clear to me what is wrong with this code, and that we can do something in this repo to fix this.

Hi @kzaher

I hope you are doing well. :)

Following the UIScrollView and RxScrollViewDelegateProxy example I made RxGIDSignInDelegateProxy.

GIDSignIn has delegate:

@property(nonatomic, weak) id<GIDSignInDelegate> delegate;

UIScrollView has delegate:

weak open var delegate: UIScrollViewDelegate?

When I add:

extension GIDSignIn: HasDelegate {
    public typealias Delegate = GIDSignInDelegate
}

I get:

Type 'GIDSignIn' does not conform to protocol 'HasDelegate'

I assume It's probably swift/associatedtype and objc protocol compatibility issue or am I missing something?

Cheers,
Ivan

My RxGIDSignInDelegateProxy works without:

extension GIDSignIn: HasDelegate

Cool. Closing this not a bug issue. :)

Cheers,
Ivan

For me it's giving
Delegate proxy is already implementingsignIn:didSignInForUser:withError:, a more performant way of registering might exist.

error can anybody help?

TIA

Hey @VinayakDeshpande11,

Here is my implementation. Works without warnings.

Cheers,
Ivan

import RxSwift
import RxCocoa

open class RxGIDSignInDelegateProxy: DelegateProxy<GIDSignIn, GIDSignInDelegate>, DelegateProxyType, GIDSignInDelegate {
    public weak private(set) var gidSignIn: GIDSignIn?
    var signInSubject = PublishSubject<GIDGoogleUser>()
    var disconnectSubject = PublishSubject<GIDGoogleUser>()

    public init(gidSignIn: ParentObject) {
        self.gidSignIn = gidSignIn
        super.init(parentObject: gidSignIn, delegateProxy: RxGIDSignInDelegateProxy.self)
    }

    public static func registerKnownImplementations() {
        self.register { RxGIDSignInDelegateProxy(gidSignIn: $0) }
    }

    open class func currentDelegate(for object: ParentObject) -> GIDSignInDelegate? {
        return object.delegate
    }

    open class func setCurrentDelegate(_ delegate: GIDSignInDelegate?, to object: ParentObject) {
        object.delegate = delegate
    }

    public func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
        if let u = user {
            self.signInSubject.on(.next(u))
        } else if let e = error {
            self.signInSubject.on(.error(e))
        }
        self._forwardToDelegate?.sign(signIn, didSignInFor: user, withError: error)
    }

    public func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
        if let u = user {
            self.disconnectSubject.on(.next(u))
        } else if let e = error {
            self.disconnectSubject.on(.error(e))
        }
        self._forwardToDelegate?.sign(signIn, didDisconnectWith: user, withError: error)
    }

    deinit {
        self.signInSubject.on(.completed)
        self.disconnectSubject.on(.completed)
    }
}

extension Reactive where Base: GIDSignIn {
    public var delegate: DelegateProxy<GIDSignIn, GIDSignInDelegate> {
        return self.gidSignInDelegate
    }

    private var signIn: Single<GIDGoogleUser> {
        let proxy = self.gidSignInDelegate
        proxy.signInSubject = PublishSubject<GIDGoogleUser>()
        return proxy.signInSubject
            .asObservable()
            .do(onSubscribed: {
                proxy.gidSignIn?.signIn()
            })
            .take(1)
            .asSingle()
    }

    private var signOut: Single<GIDGoogleUser> {
        let proxy = self.gidSignInDelegate
        proxy.signInSubject = PublishSubject<GIDGoogleUser>()
        return proxy.disconnectSubject
            .asObservable()
            .do(onSubscribed: {
                proxy.gidSignIn?.signOut()
            })
            .take(1)
            .asSingle()
    }

    private var gidSignInDelegate: RxGIDSignInDelegateProxy {
        return RxGIDSignInDelegateProxy.proxy(for: base)
    }
}

Hi Ivan,
Thanks a lot for sharing the implementation, but now I am stuck with the subscription part. How will I subscribe this on the button tap? please let me know that would be of great help.

I tried with GIDSignIn().sharedInstance.rx.signIn but it didn't work.

TIA

Hi Ivan,
It worked for me but I had to remove the private from private var signIn: Single<GIDGoogleUser> from reactive extension. Please let me know if there is a work around without removing the private modifier.

TIA

@VinayakDeshpande11 that's fine ;)

How to call this method to get Auth Token.
GIDSignIn().sharedInstance.rx.signIn doesn't work
Neither return GIDSignIn.sharedInstance().rx.base.signIn()

i have method like this
here return type is Auth of Google

private func loginGoogle() -> Single {
return GIDSignIn.sharedInstance().rx.base.signIn()
}
Although methods are striken through in suggestion.

screen shot 2018-09-12 at 1 20 46 pm
screen shot 2018-09-12 at 1 20 59 pm

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gaudecker picture gaudecker  路  3Comments

lyricsboy picture lyricsboy  路  3Comments

tyregor picture tyregor  路  3Comments

jaumard picture jaumard  路  3Comments

jeremiegirault picture jeremiegirault  路  3Comments