Search code examples
objective-coauth-2.0swiftselectorgtm-oauth2

Can't get Selector to work for my Swift Function


I have a mixed Swift and Objective C application. The swift app uses some ObjectiveC libaries to handle OAuth2 authentication. Part of that is a callback to a delegate method once the OAuth2 request for a token has completed.

The following code is being executed in an Objective C library (GTMOAuth2) which uses a selector which I have passed in:

if (delegate_ && finishedSelector_) {
  SEL sel = finishedSelector_;
  NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel];
  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
  [invocation setSelector:sel];
  [invocation setTarget:delegate_];
  [invocation setArgument:&self atIndex:2];
  [invocation setArgument:&auth atIndex:3];
  [invocation setArgument:&error atIndex:4];
  [invocation invoke];
}

The function I'd like this to invoke is in my swift viewController and looks like such:

func authentication(viewController: GTMOAuth2ViewControllerTouch, finishedWithAuth: GTMOAuth2Authentication, error: NSError)
{
    if (error != nil)
    {
        var alertView: UIAlertView = UIAlertView(title: "Authorisation Failed", message: error.description, delegate: self, cancelButtonTitle: "Dismiss")

        alertView.show()

    }
    else
    {
        // Authentication Succeeded
        self.mytoken = finishedWithAuth.accessToken
    }
}

The selector I am currently passing in is:

let mySelector: Selector = Selector("authentication:viewController:finishedWithAuth:error:")

and is being used as a parameter in this call:

let myViewController: GTMOAuth2ViewControllerTouch = GTMOAuth2ViewControllerTouch(authentication: auth, authorizationURL: authURL, keychainItemName: nil, delegate: self, finishedSelector: mySelector)

Can anyone tell me why my function is never being called? It always seems to fail on the line where it creates an NSInvocation.

I've tried multiple selector strings and each one seems to fail. Am I missing something?

I've also tried putting "@objc" in front of the func name, to no avail.


Solution

  • The Swift method

    func authentication(viewController: GTMOAuth2ViewControllerTouch,
                      finishedWithAuth: GTMOAuth2Authentication,
                                 error: NSError)
    

    is exposed to Objective-C as

    -(void)authentication:(GTMOAuth2ViewControllerTouch *) viewController 
         finishedWithAuth:(GTMOAuth2Authentication *) finishedWithAuth
                    error:(NSError *)error
    

    which means that the selector is

    Selector("authentication:finishedWithAuth:error:")
    

    Generally, the first parameter name is not part of the selector. The only exception are init methods, where the first parameter name is merged into the Objective-C method name. For example, the Swift initializer

    init(foo: Int, bar: Int) 
    

    translates to Objective-C as

    - (instancetype)initWithFoo:(NSInteger)foo bar:(NSInteger)bar
    

    and the selector would be

    Selector("initWithFoo:bar:")