xcode Swift 3 - 发送同步 http 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40491502/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swift 3 - Send make synchronous http request
提问by Alec.
I have the following code:
我有以下代码:
func completeLoadAction(urlString:String) -> Int {
let url = URL(string:urlString.trimmingCharacters(in: .whitespaces))
let request = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
let ac = UIAlertController(title: "Unable to complete", message: "The load has been added to the completion queue. This will be processed once there is a connection.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
return
}
let httpStatus = response as? HTTPURLResponse
var httpStatusCode:Int = (httpStatus?.statusCode)!
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
let ac = UIAlertController(title: "Completed Successfully", message: "The "+coldel+" has been completed successfully", preferredStyle: .alert)
ac.addAction(UIAlertAction(title:"Continue", style: .default, handler: { action in self.performSegue(withIdentifier: "segueConfirmedLoad", sender: self) }))
self.present(ac, animated: true)
}
task.resume()
return httpStatusCode
}
I need to be able to call this and at the same time check the return value as it is the http status code, it will let me know if the call was successful or not.
我需要能够调用它,同时检查返回值,因为它是 http 状态代码,它会让我知道调用是否成功。
Problem is because it's in a dataTask I can't access the responses status code here
问题是因为它在 dataTask 中,我无法在此处访问响应状态代码
var httpStatusCode:Int = (httpStatus?.statusCode)!
Because the task doesn't start until Task.Resume() is called and the task is asynchronous so it will never work.
因为在调用 Task.Resume() 之前任务不会启动,并且任务是异步的,所以它永远不会工作。
Are there any ways around this?
有没有办法解决这个问题?
回答by darren102
To make it synchronous and wait you can use semaphores such as below
要使其同步并等待,您可以使用如下信号量
struct Login {
static func execute() -> Bool {
let request = NSURLRequest....
var success = false
let semaphore = DispatchSemaphore(value: 0)
let task = URLSession.shared.dataTask(with: request, completionHandler: { _, response, error in
if let error = error {
print("Error while trying to re-authenticate the user: \(error)")
} else if let response = response as? HTTPURLResponse,
300..<600 ~= response.statusCode {
print("Error while trying to re-authenticate the user, statusCode: \(response.statusCode)")
} else {
success = true
}
semaphore.signal()
})
task.resume()
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
return success
}
}
回答by vadian
There is always a way to use the asynchronous pattern.
总有一种方法可以使用异步模式。
To make the function asynchronous add a completion block
为了使函数异步添加一个完成块
func completeLoadAction(urlString:String, completion: (Int) -> ()) {
let url = URL(string:urlString.trimmingCharacters(in: .whitespaces))
let request = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
DispatchQueue.main.async {
let ac = UIAlertController(title: "Unable to complete", message: "The load has been added to the completion queue. This will be processed once there is a connection.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
completion(0) // or return an error code
return
}
let httpStatus = response as? HTTPURLResponse
var httpStatusCode:Int = (httpStatus?.statusCode)!
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
DispatchQueue.main.async {
let ac = UIAlertController(title: "Completed Successfully", message: "The "+coldel+" has been completed successfully", preferredStyle: .alert)
ac.addAction(UIAlertAction(title:"Continue", style: .default, handler: { action in self.performSegue(withIdentifier: "segueConfirmedLoad", sender: self) }))
self.present(ac, animated: true)
}
completion(httpStatusCode)
}
task.resume()
}
and call it thusly
并这样称呼它
completeLoadAction(urlString: "www.something.com") { code in
print(code)
}
回答by user9107690
This won't work in all situations. Suppose you are implementing a shared extension. And you are overriding the isContentValid()
method that returns a boolean (true if the content is valid)... but in order to test if the content is valid, you want to verify that the server is running (this is a contrived example). If you make an asynchronous http call--completion block or not--you cannot return the proper value of the boolean; the only way to accomplish this is to do a synchronous call and return true/false based on the return value.
这不会在所有情况下都有效。假设您正在实现一个共享扩展。并且您正在覆盖isContentValid()
返回布尔值的方法(如果内容有效,则为 true)……但是为了测试内容是否有效,您需要验证服务器是否正在运行(这是一个人为的示例)。如果您进行异步 http 调用——无论是否完成块——您都无法返回布尔值的正确值;完成此操作的唯一方法是进行同步调用并根据返回值返回真/假。
The answer that posted the semaphore pattern is the proper one to use in this case.
发布信号量模式的答案是在这种情况下使用的正确答案。