web-dev-qa-db-ja.com

HTTP POSTエラー処理Swift 2

私はここで新しく、これが私の最初の質問です... HTTP Swiftリクエストを行うPOST 2でアプリを記述しようとしますが、 Swift 2.の新しいエラー処理の使用方法がわかりません。 "do-try-catch"エラー処理の実装方法を教えてください。 of Swift 2以下のコードスニペットに?(このコードスニペットは、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

次のように、NSJSONSerialization呼び出しをdo/try/catchロジックでラップすることをお勧めします。

In 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()

または、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()

また、クラッシュではなくエラーを検出/処理するため、dataの強制的なアンラップについてもう少し注意することをお勧めします。たとえば、上記ではguardステートメントを使用して展開します。

36
Rob

一般に、関数throwsdo catchブロック内に記述するか、外部スコープ関数(この場合はpost)を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()
}

post関数でこれらのエラーを処理したくない場合は、do catchをまったく使用する必要がないので、throwsとして宣言できます。

5
Qbyte