Swift 3 - 发送make同步http请求

Ale*_*ec. 8 xcode http ios swift swift3

我有以下代码:

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
}
Run Code Online (Sandbox Code Playgroud)

我需要能够调用它并同时检查返回值,因为它是http状态代码,它会让我知道调用是否成功.

问题是因为它在dataTask中我无法访问响应状态代码

var httpStatusCode:Int = (httpStatus?.statusCode)!
Run Code Online (Sandbox Code Playgroud)

因为任务在调用Task.Resume()之前不会启动,并且任务是异步的,所以它永远不会工作.

这有什么办法吗?

dar*_*102 30

要使它同步并等待,您可以使用下面的信号量

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这是错的?你给它一个错误,但不要用任何东西支持它.同步网络在我找到的一些情况下有它的位置,我使用它.但是,大多数情况下使用异步网络.此外,问题是关于同步网络,因此我提供了同步网络响应示例的原因.同样在问题的评论中,我告知异步可以获得与完成块相同的结果.感谢您提供用户根据问题询问的答案. (9认同)
  • Rob我理解为什么我在评论中说明了它可以异步完成.我只是觉得很奇怪被告知我错了,并且投票给了问题的答案.无论如何不要担心它,只是觉得很奇怪,因为提出问题的有效答案而被投了票. (9认同)
  • 你是对的,有些情况下需要同步网络。这不是其中之一。通常,当有人问如何“等待网络请求”时,只是因为他们不熟悉或不习惯异步模式,而不是因为他们真的需要同步代码。恕我直言,同步模式引入了如此多的潜在问题,以至于在不讨论危险的情况下向他们展示如何做到这一点是不明智的。Apple 出于某种原因停用了同步网络 API。 (2认同)
  • 同意@darren102:我正在编写一个测试,需要从后门服务器获取数据,然后我将其作为测试的一部分进行验证.我通过谷歌找到了这个答案,标题正是我所寻找的.我很欣赏原来的问题可能不是一个正确的问题,但这是正确的答案. (2认同)

vad*_*ian 12

总有一种方法可以使用异步模式.

要使函数异步,请添加完成块

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

}
Run Code Online (Sandbox Code Playgroud)

并且这样称呼它

completeLoadAction(urlString: "www.something.com") { code in
   print(code)
}
Run Code Online (Sandbox Code Playgroud)