romero-ios
romero-ios

Reputation: 1085

Xcode 8 seems to be incorrectly changing embedded framework function signature with Swift 3

I have a linked framework that has a class called LoginViewController.h

With Swift 2.3, using this class worked just fine. The function in question is this one:

-(void)startLoginWithSuccessHandler: (LoginSuccessHandler)successHandler failureHandler:(LoginFailureHandler)failureHandler;

At the top of the class there are some typedefs:

typedef void (^LoginSuccessHandler)();
typedef void (^LoginFailureHandler)(NSError *error);

I have a function that calls startLoginWithSuccessHandler( ):

func showLogin(){
    //Does some stuff
    loginViewController.startLoginWithSuccessHandler( { () -> Void in
       //Does more stuff

       }) { (error:NSError!) -> Void in
          //More stuff
       }
}

As you see above, this code worked just fine and my app runs and performs as expected.

When I used the Swift 3 migration tool, one of the errors came from this function call. It appears Xcode completely changed the way the method was called:

func showLogin() {
     //Does some stuff
     loginViewController.startLogin(successHandler: { () -> Void in
        //Does more stuff

       }) { (error:NSError!) -> Void in
           //More stuff
       }
}

It is clear that Xcode tried to convert the method signature to match the new Swift 3 conventions. However, this is a function inside a framework written in Obj-C, so the actual function is supposed to remain the way it is.

Furthermore, the actual error I am getting in Xcode occurs with this line:

{ (error:NSError!) -> Void in

And it says:

Cannot convert value of type '(NSError!) -> Void' to expected argument type 'LoginFailureHandler!'

I'm wondering if this is a bug or if there is an actual workaround/fix for this.

Upvotes: 2

Views: 141

Answers (1)

OOPer
OOPer

Reputation: 47896

You have no need to worry about this: this is a function inside a framework written in Obj-C, so the actual function is supposed to remain the way it is.

Swift has some mapping rule and it generates the right Objective-C selectors for methods imported from Objective-C code.

You can find this code (put it where loginViewController is visible) showing true.

print(#selector(loginViewController.startLogin(successHandler:failureHandler:))
    == Selector("startLoginWithSuccessHandler:failureHandler:"))

And with this:

{ (error:NSError!) -> Void in

Swift 3 imports NSError as Error. Try changing the line with this:

{ (error: Error?) -> Void in

If you want to use it as NSError, simple as casting should work:

let nsError = error as NSError?

Upvotes: 2

Related Questions