使用XCode-8.2.1,Swift-3.0.2和iOS-10.2.1,
我正在尝试调用两个不同的URLSession.shared.dataTasks(第一个是简单的URL请求,第二个是POST请求)。
由于我的第一个dataTask提供了第二个dataTask的httpBody所需的结果,因此两个URLSession.shared.dataTasks将一个接一个地串行运行! (以及准备代码应连续运行)。
到目前为止,我尝试使用两个连续的serialQueue.sync{}
个队列。但我必须意识到代码没有按照我想要的顺序执行。
日志中的print语句结果如下:
Hmmmmmm 2
Hmmmmmm 1
Hmmmmmm 3
(根据需要代替1,2,3)!
如何获得订单1,2,3
(即如何确保第二个dataTask的httpBody可以填充来自第一个dataTask的结果?)
这是我的代码:(不可执行,因为网址已被删除 - 但您明白了这一点)!
import UIKit
class ViewController: UIViewController {
let serialQueue = DispatchQueue(label: "myResourceQueue")
var stationID: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.serialQueue.sync {
let myResourceURL = URL(string: "myQueryString1")
let task = URLSession.shared.dataTask(with: myResourceURL!) { (data, response, error) in
if (error != nil) {
// print(error.debugDescription)
} else {
if let myData = data {
do {
let myJson = try JSONSerialization.jsonObject(with: myData, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
// print(myJson)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print("Hmmmmmm 1")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
} catch {
// error
}
}
}
}
task.resume()
}
self.serialQueue.sync {
var request = URLRequest(url: URL(string: "myQueryString2")!)
request.httpMethod = "POST"
request.addValue("API_id", forHTTPHeaderField: "Authorization")
request.addValue("application/xml", forHTTPHeaderField: "Content-Type")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print("Hmmmmmm 2")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
let postString: String = "My_XML_POST_Body"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print("Hmmmmmm 3")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
task.resume()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
任何帮助表示赞赏!
答案 0 :(得分:4)
我终于找到了解决方案:
受到this answer的启发,我引入了URLSessionDataDelegate
及其委托回调方法(即didReceive response:
,didReceive data:
和didCompleteWithError error:
。
重要提示:您需要使用委托设置URLSession,以使引入的URLSessionDelegate的回调方法有效:使用URLSession(配置:....),如下所示:
let URLSessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: URLSessionConfig, delegate: self, delegateQueue: OperationQueue.main)
在那之后,你很高兴,即现在正如预期的那样:
Hmmmmmm 1
Hmmmmmm 2
Hmmmmmm 3
这是最终的代码(再次不能执行,因为URL已被取出 - 但你明白了这一点)!
import UIKit
class ViewController: UIViewController, URLSessionDataDelegate {
var stationID: Int = 0
let URLSessionConfig = URLSessionConfiguration.default
var session: URLSession?
var task1: URLSessionTask?
var task2: URLSessionTask?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.session = URLSession(configuration: URLSessionConfig, delegate: self, delegateQueue: OperationQueue.main)
// prepare dataTask Nr 1
let myResourceURL = URL(string: "myQueryString1")
self.task1 = session?.dataTask(with: myResourceURL!)
// start dataTask Nr 1 (URL-request)
self.task1?.resume()
}
// Optional: Use this method if you want to get a response-size information
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
// print(Int(response.expectedContentLength))
completionHandler(URLSession.ResponseDisposition.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
if dataTask == self.task1 {
do {
let myJson = try JSONSerialization.jsonObject(with: myData, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
// print(myJson)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print("Hmmmmmm 1")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// prepare dataTask Nr 2
self.task2 = self.session?.dataTask(with: self.prepareMyURLRequest())
} catch {
// error
}
} else if dataTask == self.task2 {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print("Hmmmmmm 3")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
} else {
print("unknown dataTask callback")
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if (error != nil) {
// print(error.debugDescription)
} else if task == self.task1 {
// start dataTask Nr 2 (POST URL-request)
self.task2?.resume()
}
}
func prepareMyURLRequest() -> URLRequest {
var request = URLRequest(url: URL(string: "myQueryString2")!)
request.httpMethod = "POST"
request.addValue("API_id", forHTTPHeaderField: "Authorization")
request.addValue("application/xml", forHTTPHeaderField: "Content-Type")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print("Hmmmmmm 2")
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
let postString: String = "My_XML_POST_Body"
request.httpBody = postString.data(using: .utf8)
return request
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
答案 1 :(得分:0)
如果task2需要task1的结果,你应该从task1
的完成块启动task2URLSession.shared.dataTask(with: request) { data, response, error in
// process task1 and setup request2
URLSession.shared.dataTask(with: request2) { data, response, error in
// process task2
}.resume()
}.resume()
当然,对于多个请求,这会有点笨拙,所以最好使用Promises&期货。 Promise&有几种实现方式。 Swift的期货,例如Promis