在SO上使用了几个答案,我们设法编写并执行了一个基本的HTTP请求:
import Foundation
let url:URL = URL(string: "http://jsonplaceholder.typicode.com/posts")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
let paramString = "data=Hello"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString: String = String(data: data, encoding: String.Encoding.utf8)!
print("here")
print("Data: \(dataString)")
print("Response: \(response!)")
}
task.resume()
while task.response == nil {}
print("Done")
您注意我们已经忙碌 - 等到task.response
设置完毕。但是,数据和响应均未打印,仅为here
。
经过无休止的尝试,我们在这里或那样包装东西,我们确定我们在这里有一个Heisenbug:代码中没有任何改变,有时会打印here
,有时候什么都没有,而且非常非常罕见dataString
(更不用说response
)。
所以我们在sleep(3)
之前插入print("Done")
,奇迹奇迹,我们得到所有的印刷品。
然后我们大声喊叫(我实际上可能已经抛出了一些东西),简单地想一想放弃Swift,但后来平静下来,像sirs一样面对并发布在这里。
显然,主线程终止是否有任何异步任务(线程?)仍然在运行,从而终止所有的spawn。我们怎样才能防止这种情况发生,即"加入"线程?
奖金问题: Alamofire是否在幕后处理这个问题?
答案 0 :(得分:0)
使用Matt Gallagher的CwUtils,我实现了一个简单的CountdownLatch
来完成工作:
import Foundation
import CwlUtils
<...>
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
<...>
latch.countDown()
}
task.resume()
latch.await()
答案 1 :(得分:0)
积极等待似乎是GCD的唯一途径。使用标准库材料,这是有效的:
import Foundation
<...>
var done = false
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
<...>
done = true
}
task.resume()
repeat {
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
} while !done
答案 2 :(得分:-1)
最直接(和内置)方式可能是使用DispatchSemaphore
:
<...>
let sem = DispatchSemaphore(value: 0)
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
<...>
sem.signal()
}
task.resume()
sem.wait()