當我想在 swift 5.5 中將我的 API 請求重構為新的 async/await 功能時遇到問題。
我的代碼是(我洗掉了所有憑據和個人資訊,但邏輯是相同的):
class API {
enum HTTPMethods: String {
case GET = "GET"
case POST = "POST"
}
// Credentials
private let testKey = "abcdef"
private var authenticationHeaders: [String: String] = ["username": "myUsername",
"password": "myPassword"]
private var token: String = "MyToken"
// Data collected from the API requests
private var a: Response1?
private var b: Response2?
// Base URLs
private var url = "https://example.com"
// Singleton
static let singleton = API()
private init() {
// Increasing the interval for the timeout
URLSession.shared.configuration.timeoutIntervalForRequest = 530.0
URLSession.shared.configuration.timeoutIntervalForResource = 560.0
}
private func getRequest(url: URL, method: HTTPMethods) -> URLRequest{
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Token \(token)", forHTTPHeaderField: "Authorization")
return request
}
private func checkResponse(response: URLResponse?, nameRequest: String){
if let httpResponse = response as? HTTPURLResponse {
switch httpResponse.statusCode {
case 200...201:
print("URL request made successfully!")
default:
fatalError("Error in the request \(nameRequest), status code \(httpResponse.statusCode), response: \(String(describing: response))")
}
}
}
func makeAuthorization() async {
let url = URL(string: url)!
var request = getRequest(url: url, method: HTTPMethods.POST)
// Insert json data to the request
if let jsonData = try? JSONSerialization.data(withJSONObject: authenticationHeaders) {
request.httpBody = jsonData
}
do {
let (data, response) = try await URLSession.shared.data(for: request)
if let response = try? JSONDecoder().decode(Response1.self, from: data) {
token = response.token
}
checkResponse(response: response, nameRequest: "Authorization")
} catch {
fatalError("Request failed with error: \(error)")
}
}
func getTestConfiguration() async {
let url = URL(string: url)!
let request = getRequest(url: url, method: HTTPMethods.GET)
do {
let (data, response) = try await URLSession.shared.data(for: request)
if let response = try? JSONDecoder().decode(Response2.self, from: data) {
self.b = response
}
checkResponse(response: response, nameRequest: "getTestConfiguration")
} catch {
fatalError("Request failed with error: \(error)")
}
}
}
struct Response1: Codable {
let token: String
}
struct Response2: Codable {
let token: String
}
我試圖重構的代碼,舊方式的原始代碼,是:
func makeAuthorizationO() {
if let urlObject = URL(string: url) {
var request = getRequest(url: urlObject, method: HTTPMethods.POST)
// Insert json data to the request
if let jsonData = try? JSONSerialization.data(withJSONObject: authenticationHeaders) {
request.httpBody = jsonData
}
URLSession.shared.dataTask(with: request) { [self] data, response, error in
guard error == nil,
let _ = data else {
print(error ?? "Error in makeAuthorization, but error is nil")
return
}
if let unwrappedData = data {
if let response = try? JSONDecoder().decode(Response1.self, from: unwrappedData) {
token = response.token
print("makeAuthorization successful!")
}
}
checkResponse(response: response, nameRequest: "Authorization")
}.resume()
}
}
func getTestConfigurationO(){
if let urlObject = URL(string: url) {
URLSession.shared.dataTask(with: getRequest(url: urlObject, method: HTTPMethods.GET)) { data, response, error in
guard error == nil,
let _ = data else {
print(error ?? "Error in getTestConfiguration, but error is nil")
return
}
if let unwrappedData = data {
let decoder = JSONDecoder()
if let test = try? decoder.decode(Response2.self, from: unwrappedData) {
self.b = test
}
}
self.checkResponse(response: response, nameRequest: "TestConfiguration")
}.resume()
}
}
問題是,使用新代碼時,出現以下錯誤:
Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://example.com, NSErrorFailingURLKey=https://example.com, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <3B064821-156C-481C-8A72-30BBDEE5218F>.<3>"
我完全不知道這里發生了什么,更令人困惑的是,大多數時候錯誤并不總是發生,但有時代碼會正確執行。這種行為和這個錯誤有什么問題?PD:原始代碼,在更改為 async/await 之前總是可以正常作業
我呼叫該方法的方式是在主視圖的出現上:
struct MyView: View {
var body: some View {
VStack {
Text("My message")
}.task {
let api = API.singleton
await api.makeAuthorization()
await api.getTestConfiguration()
}
}
}
uj5u.com熱心網友回復:
取消父任務時會發生異步 URL 會話資料任務的取消錯誤,例如,如果從視圖層次結構中洗掉 MyView。這是正在發生的事情嗎?
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/313649.html
上一篇:在Swift中的ScrollView中設定子ViewController高度
下一篇:無指標解除參考
