0

我想为我的服务器编写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
}
4

2 回答 2

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)
于 2016-11-25T18:05:24.193 回答
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
于 2016-11-25T18:09:05.573 回答