Swift http请求使用urlSession

时间:2016-11-25 17:36:57

标签: swift http request urlsession

我想为我的服务器编写HTTP请求的func并获取一些数据,当我打印它(print(responseString))它看起来不错,但是当我尝试返回数据时,它总是空的

public func HTTPRequest(dir: String, param: [String:String]?) -> String{
    var urlString = HOST + dir + "?"
    var responseString = ""
    if param != nil{
        for currentParam in param!{
            urlString += currentParam.key + "=" + currentParam.value + "&"
        }
    }

    let url = URL(string: urlString)

    let task = URLSession.shared.dataTask(with: url!) { data, response, error in
        guard error == nil else {
            print("ERROR: HTTP REQUEST ERROR!")
            return
        }
        guard let data = data else {
            print("ERROR: Empty data!")
            return
        }
        responseString = NSString(data: data,encoding: String.Encoding.utf8.rawValue) as! String
        print(responseString)
    }
    task.resume()
    return responseString
}

2 个答案:

答案 0 :(得分:0)

正如Rob的评论中所提到的,dataTask闭包是异步运行的。您可能希望提供完成闭包,然后在dataTask完成时调用它,而不是立即返回值。

以下是一个示例(用于测试,可以按原样粘贴到Xcode Playground):

import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

let HOST = "http://example.org"

public func HTTPRequest(dir: String, param: [String: String]?,  completion: @escaping (String) -> Void) {

    var urlString = HOST + dir + "?"

    if param != nil{
        for currentParam in param! {
            urlString += currentParam.key + "=" + currentParam.value + "&"
        }
    }

    let url = URL(string: urlString)

    let task = URLSession.shared.dataTask(with: url!) { data, response, error in
        guard error == nil else {
            print("ERROR: HTTP REQUEST ERROR!")
            return
        }
        guard let data = data else {
            print("ERROR: Empty data!")
            return
        }
        let responseString = NSString(data: data,encoding: String.Encoding.utf8.rawValue) as! String

        completion(responseString)

    }

    task.resume()

}

let completion: (String) -> Void = { responseString in

    print(responseString)

}

HTTPRequest(dir: "", param: nil, completion: completion)

答案 1 :(得分:0)

您需要使用完成块而不是返回值,因为dataTask闭包是异步运行的,即稍后,从您的方法返回后。您不想尝试立即返回该值(因为您还没有它)。你想(a)改变这个函数不返回任何东西,但是(b)提供一个完成处理程序闭包,你将在dataTask闭包中调用它来构建responseString。

例如,您可以这样定义它:

public func HTTPRequest(dir: String, param: [String:String]? = nil, completionHandler: @escaping (String?, Error?) -> Void) {
    var urlString = HOST + dir

    if let param = param {
        let parameters = param.map { return $0.key.percentEscaped() + "=" + $0.value.percentEscaped() }
        urlString += "?" + parameters.joined(separator: "&")
    }

    let url = URL(string: urlString)

    let task = URLSession.shared.dataTask(with: url!) { data, response, error in
        guard let data = data, error == nil else {
            completionHandler(nil, error)
            return
        }
        let responseString = String(data: data, encoding: .utf8)
        completionHandler(responseString, nil)
    }
    task.resume()
}

注意,我是使用类似的东西来逃避参数字典中的值的百分比:

extension String {

    /// Percent escapes values to be added to a URL query as specified in RFC 3986
    ///
    /// This percent-escapes all characters besides the alphanumeric character set and "-", ".", "_", and "~".
    ///
    /// http://www.ietf.org/rfc/rfc3986.txt
    ///
    /// - Returns: Returns percent-escaped string.

    func percentEscaped() -> String {
        let allowedCharacters = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~")

        return self.addingPercentEncoding(withAllowedCharacters: allowedCharacters)!
    }

}

然后你会这样称呼它:

HTTPRequest(dir: directory, param: parameterDictionary) { responseString, error in
    guard let responseString = responseString else {
        // handle the error here
        print("error: \(error)")
        return
    }

    // use `responseString` here

    DispatchQueue.main.async {
        // because this is called on background thread, if updating
        // UI, make sure to dispatch that back to the main queue.
    }
}

// but don't try to use `responseString` here