2017-02-15 131 views
1

上所以使用幾個答案,我們已經成功地編寫並執行一個基本的HTTP請求:我們如何等待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)。

所以我們在print("Done")之前插入sleep(3),奇蹟般的奇蹟,我們得到所有的照片。

然後我們大喊一聲(我可能實際上已經拋出了一些東西),想到了完全放棄Swift的想法,但是然後足夠平靜下來,像面向前輩一樣,在這裏貼上了標籤。

顯然,主線程會終止是否有任何異步任務(線程?)仍在運行或不運行,從而導致其所有產生的事件都被終止。我們如何防止這種情況發生,即「加入」線索?

獎勵問題: Alamofire會在封面背後處理這個問題嗎?

+0

[密切相關的問題(http://stackoverflow.com/questions/26784315/can-i-somehow-do-a-synchronous-http-request-通過-nsurlsession功能於SWIFT)。 – Raphael

回答

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 
0

由馬特·加拉格爾使用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

最直接的(並且內置)的方式可能是使用一個DispatchSemaphore

<...> 

let sem = DispatchSemaphore(value: 0) 

let task = session.dataTask(with: request as URLRequest) { 
    (data, response, error) in 

    <...> 
    sem.signal() 
} 

task.resume() 
sem.wait() 
+0

下降者請解釋他們爲什麼認爲這是一個不好的解決方案,理想情況下提出一個更好的選擇? – Raphael

+0

如果在sem.signal()之前異步任務向主隊列發送某些內容(或者任意一個隊列'sem.wait()'阻塞),則會出現問題。那麼我們有一個死鎖,如[見](http://stackoverflow.com/q/42644111/539599)所示。 – Raphael