completion handler's error in swift 3 and Xcode 8

13,230

Solution 1

Though I didn't know the error before that what Xcode want to inform me about the error, but I have removed type specification with object and it worked.

As

manager.post(methodname, parameters: param, progress: nil, success:{ (dataTask, responseObj) in

                if let dict : NSDictionary = responseObj as? NSDictionary {

                    print("Response of \(methodname) : \(dict)")

                    if dict.object(forKey: "response") as? String == "success" {
                        CompletionHandler(true, dict)
                    } else {
                        CompletionHandler(false, dict)
                    }


                }

        })

Here with respect to question error is given at dataTask and responseObj which are with type specified. After removing type it worked fine.

Same as with facebook login

@IBAction func fbLoginClicked(_ sender: AnyObject) {

        let app = UIApplication.shared.delegate as! AppDelegate

        app.fbLoginManager = FBSDKLoginManager()
        app.fbLoginManager.logOut()
        app.fbLoginManager.loginBehavior = FBSDKLoginBehavior.native


        app.fbLoginManager.logIn(withReadPermissions: ["email"], from: self, handler: { (result, error) -> Void in
            if error != nil {
                print(error?.localizedDescription)
            } else {

                if (result! as FBSDKLoginManagerLoginResult).isCancelled == true {

                } else {

                    self.fetchFacebookUserDetail()
                }
            }
        })

    }

Here also I have removed type specification of result and error and problem solved. And followed this in whole app and it worked. I can run the project without error and also it is working. Thanks.

Solution 2

For facebook - the problem is in new Swift rules about converting objective-c function parameters into Swift.

Previously, if parameters in objective-c code did not have nullability attributes(like nonnull or nullable), Swift converts it with ! making them non optional(forced unwrapping). Now it convert it with ? making them optional. That why you are getting an error. Before you were putting as a callback for login:

(FBSDKLoginManagerLoginResult!, NSError!) -> Void

Now you need to put:

(FBSDKLoginManagerLoginResult?, Error?) -> Void

Also, as you see, now you will not see NSError class. Instead of that Swift will put Error.This is also new rule. Now all "NS" prefixed in class names is removed in Swift(NSObject -> Object; NSError -> Error).

Example of working code for facebook login in Swift 3.0:

let manager = FBSDKLoginManager()

manager.logIn(withReadPermissions: ["public_profile"], from: self.controller) {
    (loginResult: FBSDKLoginManagerLoginResult?, error: Error?) in

}

Example of working code for facebook request in Swift 3.0:

let request = FBSDKGraphRequest()

request.start {
     (connection: FBSDKGraphRequestConnection?, result: Any?, error: Error?) in

}

As you see, now it is using Any type instead of objective-c id. In Swift 2.2 it was using AnyObject. It is also new Swift converting rule.

You do not need to specify callback parameters type. I did that in code for highlighting their real types. So you can just write code without them:

let manager = FBSDKLoginManager()

manager.logIn(withReadPermissions: ["public_profile"], from: self.controller) { (loginResult, error) in }


let request = FBSDKGraphRequest()

request.start { (connection, result, error) in }

But you need to remember that they are optional now.

In conclusion some converting rules that may affect you callback code:

  1. Closure parameters are optional if in objective-c are not specified nullability attributes
  2. All "NS" prefixes is removed for objective-c classes in Swift
  3. If objective-c function had id parameter, in Swift 3.0 it will have type Any instead of AnyObject
Share:
13,230

Related videos on Youtube

Max
Author by

Max

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.

Updated on July 09, 2022

Comments

  • Max
    Max almost 2 years

    I have working project in Xcode 7.3 with swift 2.2 version. Now I have updated Xcode 8 and migrated to swift 3. Now my project contains errors specially for blocks like success block of afnetworking.

    Snapshot for error in afnetworking post method

    Which gives error as

    Cannot convert value of type '() -> ()' to expected argument type '((URLSessionDataTask, Any?) -> Void)?'
    

    I don't understand how to solve this to work as per swift 3.

    And there is also same like error in Facebook login.

    Facebook Login error

    Which gives error as

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

    and

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

    This all errors are related to handler blocks in swift 3. I don't understand the errors and so that can't able to solve. Any help will be appreciated. Thanks in advance.

  • Vasyl Khmil
    Vasyl Khmil over 7 years
    @Max see code example from my project that is working. I put there also the definition of callback parameters type to show what exactly it is, but it is non necessary.
  • Max
    Max over 7 years
    Yes I have put same like yours then also error is there. Then I have removed :FBSDKLoginManagerLoginResult? and :Error? then error gone.
  • Vasyl Khmil
    Vasyl Khmil over 7 years
    @Max try to clean the project. It should work. If no, just check by your self what kind of params it need.
  • Max
    Max over 7 years
    Trying all the possibilities and solving one by one, There are lots of syntax changes.
  • Vasyl Khmil
    Vasyl Khmil over 7 years
    @Max have you managed to solve problem with facebook by changing params to optional?
  • Max
    Max over 7 years
    Just removed that optional?. Like - handler: { (result, error) -> Void in
  • Lena Bru
    Lena Bru over 7 years
    Half of your answer helped me VERY much. I was hoping you could help me complete the other half. I have a delegate method that accepts an NSError from objective c, but when I convert it to swift, I cant figure out the syntax, it complains that my class doesnt conform to the protocol it came from...
  • Max
    Max over 7 years
    @LenaBru Because NSError becomes Error in swift 3, so change your method accordingly.
  • Lena Bru
    Lena Bru over 7 years
    to get the userInfo member, I have to cast it "as! NSError" ... this is so horrible...
  • Max
    Max over 7 years
    @LenaBru. I have faced same. I also need userInfo from NSError because I got response in json from server with error code 400 and json but I can't get those information now by this methods. So I have changed afnetworking to alamofire now.
  • Nikola Lukic
    Nikola Lukic over 7 years
    I need help : i always get a loginResult?.isCancelled ?
  • Max
    Max over 7 years
    @NikolaLukic Post a question which shows code what you have done so that you get help to find problem and it's appropriate solution.
  • Nikola Lukic
    Nikola Lukic over 7 years
    @Max Here is : stackoverflow.com/questions/39506833/… i post github project also .
  • felixwcf
    felixwcf over 7 years
    I'm getting warning of "Expression of type 'URLSessionDataTask?' is unused". Can anyone help?
  • Max
    Max over 7 years
    @Felix just replace dataTask object with _ (underscore)
  • felixwcf
    felixwcf over 7 years
    Fixed by adding .resume(). My mistake. Mine is GET request.