我想創建一個 URL 請求并將其傳遞給 async let 系結,這對我來說似乎很自然:
func test() async {
// Force unwraps (!) are just for demo
var request = URLRequest(url: URL(string:"https://stackoverflow.com")!)
request.httpMethod = "GET" // just for example
// some more tinkering with `request` here.
// ?? Error on this line: "Reference to captured var 'request' in concurrently-executing code"
async let responseData = URLSession.shared.data(for: request).0
// It works like this:
// let immutableRequest = request
// async let responseData = URLSession.shared.data(for: immutableRequest).0
// other stuff
print("Response body: \(String(data: try! await responseData, encoding: .utf8))")
}
為什么我會收到錯誤訊息?URLRequest是一個結構,所以當我們將它傳遞給一個函式時,該函式應該得到該結構的副本,所以如果我request在異步呼叫之后修改,它不應該影響呼叫。
我知道呼叫是異步發生的,但我希望它在呼叫點捕獲引數,然后繼續執行,就好像呼叫已經進行一樣(因此,request呼叫點的副本已傳遞到data(for: request).
此外,是否有一種方便的方法可以在不創建另一個let變數且不使用閉包進行初始化的情況下執行此操作request,例如:
let request: URLRequest = {
var result = URLRequest(url: URL(string:"https://stackoverflow.com")!)
result.httpMethod = "GET"
return result
}()
uj5u.com熱心網友回復:
正如SE-0317 - async let bindings所說:
...
async let與 a 相似let,因為它定義了一個由 . 右側的運算式初始化的區域常量=。但是,它的不同之處在于初始化運算式是在一個單獨的、并發執行的子任務中計算的。
async let子任務一遇到就開始運行。...
A
async let創建一個子任務,它繼承其父任務的優先級以及任務本地值。從語意上講,這相當于創建一個一次性的,TaskGroup它產生一個任務并回傳其結果......
group.addTask與 [ ] 函式類似,閉包是@Sendableandnonisolated,這意味著它不能訪問封閉背景關系的不可發送狀態。例如,它會導致編譯時錯誤,防止潛在的競爭條件,async let初始化器嘗試改變封閉變數:var localText: [String] = ... async let w = localText.removeLast() // error: mutation of captured var 'localText' in concurrently-executing code初始化器
async let可以參考任何可發送狀態,與任何非隔離的可發送閉包相同。
所以,不是先data(for:delegate:)復制引數to然后創建異步任務,而是反過來。
通常,如果您使用閉包,您只需添加request到閉包的捕獲串列中,但在這種情況下這是不可能的。例如,您可以使用捕獲串列創建Task自己,實作類似于async let,但具有更大的控制權:
func test() async throws {
var request = URLRequest(url: URL(string:"https://httpbin.org/get")!)
request.httpMethod = "GET" // just for example
let task = Task { [request] in
try await URLSession.shared.data(for: request).0
}
// do some more stuff in parallel
print("Response body: \(String(data: try await task.value, encoding: .utf8) ?? "Not string")")
}
顯然,您可以簡單地await使用data(for:delegate:),而不是async let,問題就消失了:
func test() async throws {
var request = URLRequest(url: URL(string:"https://httpbin.org/get")!)
request.httpMethod = "GET" // just for example
let data = try await URLSession.shared.data(for: request).0
print("Response body: \(String(data: data, encoding: .utf8) ?? "Not string")")
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/421199.html
標籤:
