web-dev-qa-db-fra.com

HTTP POST Gestion des erreurs dans Swift 2

Je suis nouveau ici, et c'est ma première question ... J'essaie d'écrire une application en Swift 2 qui fait une requête HTTP POST mais je ne peut pas comprendre comment utiliser la nouvelle gestion des erreurs de Swift 2. Quelqu'un peut-il me dire comment implémenter la gestion des erreurs "do-try-catch" de Swift 2 à l'extrait de code ci-dessous? (Cet extrait de code utilise l'ancienne gestion des erreurs de Swift 1.2)

func post(params : Dictionary<String, String>, url : String) {
    var request = NSMutableURLRequest(URL: NSURL(string: url)!)
    var session = NSURLSession.sharedSession()
    request.HTTPMethod = "POST"

    var err: NSError?
    request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil/*, error: &err*/)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
        print("Response: \(response)")
        var strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
        print("Body: \(strData)")
        var err: NSError?
        var json = NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves/*, error: &err*/) as? NSDictionary

        // Did the JSONObjectWithData constructor return an error? If so, log the error to the console
        if(err != nil) {
            print(err!.localizedDescription)
            let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("Error could not parse JSON: '\(jsonStr)'")
        }
        else {
            // The JSONObjectWithData constructor didn't return an error. But, we should still
            // check and make sure that json has a value using optional binding.
            if let parseJSON = json {
                // Okay, the parsedJSON is here, let's get the value for 'success' out of it
                var success = parseJSON["success"] as? Int
                print("Succes: \(success)")
            }
            else {
                // Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
                let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
                print("Error could not parse JSON: \(jsonStr)")
            }
        }
    })

    task!.resume()
}
16
Michael_mhr

Vous voulez probablement encapsuler vos appels NSJSONSerialization dans la logique do/try/catch comme indiqué ci-dessous.

Dans Swift 3:

var request = URLRequest(url: URL(string: urlString)!)

let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

request.httpBody = try! JSONSerialization.data(withJSONObject: parameters)

// or if you think the conversion might actually fail (which is unlikely if you built `parameters` yourself)
//
// do {
//    request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
// } catch {
//    print(error)
// }

let task = session.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {
        print("error: \(error)")
        return
    }

    // this, on the other hand, can quite easily fail if there's a server error, so you definitely
    // want to wrap this in `do`-`try`-`catch`:

    do {
        if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
            let success = json["success"] as? Int                                  // Okay, the `json` is here, let's get the value for 'success' out of it
            print("Success: \(success)")
        } else {
            let jsonStr = String(data: data, encoding: .utf8)    // No error thrown, but not dictionary
            print("Error could not parse JSON: \(jsonStr)")
        }
    } catch let parseError {
        print(parseError)                                                          // Log the error thrown by `JSONObjectWithData`
        let jsonStr = String(data: data, encoding: .utf8)
        print("Error could not parse JSON: '\(jsonStr)'")
    }
}

task.resume()

Ou, en Swift 2

let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)

let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(parameters, options: [])

// or if you think the conversion might actually fail (which is unlikely if you built `parameters` yourself)
//
// do {
//    request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
// } catch {
//    print(error)
// }

let task = session.dataTaskWithRequest(request) { data, response, error in
    guard let data = data where error == nil else {
        print("error: \(error)")
        return
    }

    // this, on the other hand, can quite easily fail if there's a server error, so you definitely
    // want to wrap this in `do`-`try`-`catch`:

    do {
        if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
            let success = json["success"] as? Int                                  // Okay, the `json` is here, let's get the value for 'success' out of it
            print("Success: \(success)")
        } else {
            let jsonStr = String(data: data, encoding: NSUTF8StringEncoding)    // No error thrown, but not NSDictionary
            print("Error could not parse JSON: \(jsonStr)")
        }
    } catch let parseError {
        print(parseError)                                                          // Log the error thrown by `JSONObjectWithData`
        let jsonStr = String(data: data, encoding: NSUTF8StringEncoding)
        print("Error could not parse JSON: '\(jsonStr)'")
    }
}

task.resume()

Je suggère également de faire un peu plus attention au déballage forcé de data, car vous voulez détecter/gérer les erreurs, pas planter. Par exemple, ci-dessus, j'utilise une instruction guard pour la déballer.

36
Rob

En général, si une fonction throws vous devez l'écrire dans un do catch bloquer ou simplement marquer la fonction de portée externe (dans ce cas post) comme throws:

func post(params : Dictionary<String, String>, url : String) {
    let request = NSMutableURLRequest(URL: NSURL(string: url)!)
    let session = NSURLSession.sharedSession()
    request.HTTPMethod = "POST"

    do {
        request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
    } catch {
        //handle error. Probably return or mark function as throws
        print(error)
        return
    }
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
        // handle error
        guard error == nil else { return }

        print("Response: \(response)")
        let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
        print("Body: \(strData)")

        let json: NSDictionary?
        do {
            json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
        } catch let dataError {
            // Did the JSONObjectWithData constructor return an error? If so, log the error to the console
            print(dataError)
            let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("Error could not parse JSON: '\(jsonStr)'")
            // return or throw?
            return
        }


        // The JSONObjectWithData constructor didn't return an error. But, we should still
        // check and make sure that json has a value using optional binding.
        if let parseJSON = json {
            // Okay, the parsedJSON is here, let's get the value for 'success' out of it
            let success = parseJSON["success"] as? Int
            print("Succes: \(success)")
        }
        else {
            // Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
            let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("Error could not parse JSON: \(jsonStr)")
        }

    })

    task!.resume()
}

Si vous ne voulez pas gérer ces erreurs directement dans votre fonction post, vous pouvez simplement le déclarer en tant que throws que vous n'avez pas besoin d'utiliser do catch du tout

5
Qbyte