Swift 3 - 发送同步http请求

时间:2016-11-08 16:07:09

标签: ios swift xcode http 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
}

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

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

var httpStatusCode:Int = (httpStatus?.statusCode)!

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

有什么方法可以解决这个问题吗?

4 个答案:

答案 0 :(得分:26)

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

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
    }
}

答案 1 :(得分: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()

}

并称之为

completeLoadAction(urlString: "www.something.com") { code in
   print(code)
}

答案 2 :(得分:0)

这不适用于所有情况。假设您正在实现共享扩展。并且您将覆盖返回布尔值的isContentValid()方法(如果内容有效,则为true)...但是为了测试内容是否有效,您要验证服务器是否正在运行(这是一个人为的例子)。如果你进行异步http调用 - 完成块或不 - 你不能返回boolean的正确值;实现此目的的唯一方法是执行同步调用并根据返回值返回true / false。

发布信号量模式的答案是在这种情况下使用的正确答案。

答案 3 :(得分:0)

您可以使用DispatchGroup进行同步网络呼叫。更多线程安全。

        let group = DispatchGroup()
        for i in 0...100 {
          group.enter()
          URLSession.shared.dataTask(with: NSURL(string: "___URL_STRING___")! as URL, completionHandler: { (data, response, error) -> Void in
                defer { group.leave() }
                print("json:\(i)")
          }).resume()
          group.wait()
        }