Tobin
Tobin

Reputation: 41

Invalid conversion from throwing function type (_,_,_) throws to non-throwing function type (Data?, Response?, URLResponse?) Void

I am new at Swift programming and I am getting an error on a "let task = URLSession. I have researched and found some of those errors but none of the answers worked for me. Here is my code and line 44 throws this error

import UIKit

class loginViewController: UIViewController {

    @IBOutlet weak var userLoginTextField: UITextField!
    @IBOutlet weak var userPasswordTextField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func loginButtonTapped(_ sender: Any) {

        let user_login = userLoginTextField.text;
        let user_passwd = userPasswordTextField.text;

        if((user_passwd?.isEmpty)! || (user_passwd?.isEmpty)!) { return; }

        //Send user data to server
        let myUrl = NSURL(string: "https://www.pcpusa.net/legacy/iOS/userLogin.php");
        var request = URLRequest(url: myUrl! as URL);
        request.httpMethod = "POST";

        let postString = "login=\(String(describing: user_login))&password=\(String(describing: user_passwd))";

        request.httpBody = postString.data(using: String.Encoding.utf8);

        **let task = URLSession.shared.dataTask(with: request){**
            data,response,error in
            if error != nil {
                print("error=\(String(describing: error))")
                return
            }

            var err: NSError?
            var json = try JSONSerialization.JSONObjectWithData(data, options: .mutableContainers, error: &err) as? NSDictionary

            if let parseJSON = json {
                var resultValue:String = parseJSON["status"] as String!;
                print("result: \(resultValue)")

                if(resultValue=="Success")
                {

                    //Login is successful
                    NSUserDefaults.standardUserDefaults().setBool(true, value(forKey: "isUserLoggedIn"));
                    NSUserDefaults.standardUserDefaults().synchronize();

                    self.dismissViewControllerAnimated(true, completion:nil);

                }

            }

        }
        task.resume()
    }
}

Upvotes: 1

Views: 1604

Answers (3)

David Rönnqvist
David Rönnqvist

Reputation: 56635

URLSession.dataTask expects a non-throwing completion handler and you are passing it a closure that throws. Because of this it fails to infer the method (in other words: it can’t find a method with that name that accepts a closure that throws).

To solve this you should catch and handle the errors that can happen when you decode the JSON.

Upvotes: 3

ABeard89
ABeard89

Reputation: 911

The key to that error message is "throwing function type". In Swift, whether or not a function can throw an error is part of its method signature. URLSession is expecting a closure/function that will not throw an error.

Therefore, if you throw an error, you must catch it.

So, you basically have two options here:

  1. Wrap the throwable try in a do-try-catch block.
  2. Use optionals to ignore possible errors and safely unwrap the result.

Example of option 1:

var json: [String: Any]!
do {
    json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
} catch let error { // `let error` is optional. It is the default.
    // Handle error here
}

Example of option 2:

(Also, I suggest using the guard statement for situations like this. This is my preferred method most of the time, and is considered by many to be more "Swifty")

let task = URLSession.shared.dataTask(with: request) {
    data,response,error in

    guard error != nil else {
        print("error=\(String(describing: error))")
        return
    }

    guard
        let data = data,
        let jsonObject = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers),
        let json = jsonObject as? [String: Any]
        else {
            print("Could not parse JSON")
            return
    }

    if let status = json["status"] as? String {
        print(status)
    }

}

EDIT: Adds surrounding context to option 2.

More on guard. It basically acts as an inside-out if-else statement.

You can use guard to test regular booleans. Or, like if, you can combine it with let to make a guard-let statement.

The difference between the two is:

  • You use if-let when you say, "If this exists, I'll do something with it. Then I'll continue."
  • You use guard-let when you say, "If I don't have this thing, then I can't continue".

Because of this, you must stop your function in its else statement, usually by returning or throwing an error (which you can't do here).

Upvotes: 1

gadu
gadu

Reputation: 1826

The problem is you try to decode (which can throw). Since you don't catch anywhere URLSession.dataTask complains because it doesn't expect that closure to throw. (If a method or closure can throw it will be marked with the throws keyword, this is an Apple provided method that does not have that keyword)

You just need to wrap in a do catch like so:

let task = URLSession.shared.dataTask(with: request){ (data,response,error) in
    if error != nil {
        print("error=\(String(describing: error))")
        return
    }

    var err: NSError?
    do {
        var json = try JSONSerialization.JSONObjectWithData(data, options: .mutableContainers, error: &err) as? NSDictionary

        if let parseJSON = json {
            var resultValue:String = parseJSON["status"] as String!;
            print("result: \(resultValue)")
        ...
    } catch {
         //print("Error: unable to serialize data: \(err)")
    }
}

Upvotes: 0

Related Questions