Swift 中的网络层、完成块和错误

  • 本文关键字:错误 网络层 Swift ios swift
  • 更新时间 :
  • 英文 :


我正在 Swift 中实现一个网络层。这是函数之一。该功能按预期工作,但我想改进它。我正在使用 DispatchQueue 来确保来自网络客户端的回调始终在主线程上。这最终会在 3 个不同的地方重复 DispatchQueue.main.async。

此外,当我在执行请求时遇到一些错误时,我仍然发回 nil 但成功。

func getAllStocks(url: String, completion: @escaping (Result<[Stock]?,NetworkError>) -> Void) {
guard let url = URL(string: url) else {
completion(.failure(.invalidURL)) // wrap in DispatchQueue also 
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
DispatchQueue.main.async {
completion(.success(nil)) // should I send nil or some sort of failure
}
return
}
let stocks = try? JSONDecoder().decode([Stock].self, from: data)
DispatchQueue.main.async {
completion(.success(stocks))
}
}
}

如何最小化代码或没问题?

Result类型的目标是在成功时返回可选类型,在失败时返回错误。

我建议在当前线程上调用completion并在调用方端调度结果。

并处理DecodingError

func getAllStocks(url: String, completion: @escaping (Result<[Stock],Error>) -> Void) {
guard let url = URL(string: url) else {
completion(.failure(NetworkError.invalidURL)) 
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error { completion(.failure(error)); return }          
// if error is nil then data has a value
do {
let stocks = try JSONDecoder().decode([Stock].self, from: data!)
completion(.success(stocks))
} catch {
completion(.failure(error))
}
}.resume()  
}

getAllStocks(url: someURL) { result in
DispatchQueue.main.async {
switch result {
case .success(let stocks): print(stocks)
case .failure(let networkError as NetworkError): handleNetworkError(networkError)
case .failure(let decodingError as DecodingError): handleDecodingError(decodingError)
case .failure(let error): print(error)
}
}
}

倾向于内置构造和标准类型。

func getAllStocks(url: String, completion: @escaping (Result<[Stock], Error>) -> Void) {
func completeOnMain(_ result: Result<[Stock], Error>) { // <-- Nested function
DispatchQueue.main.async { completion(result) } // <-- Handle repeated work
}
guard let url = URL(string: url) else {
completeOnMain(.failure(URLError(.badURL))) // <-- Standard Error
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
do {
if let error = error { throw error }
guard let data = data else { throw URLError(.badServerResponse) }
let stocks = try JSONDecoder().decode([Stock].self, from: data)
completeOnMain(.success(stocks))
} catch {
completeOnMain(.failure(error)) // <-- Unified error handling
}
}
}
  • 嵌套函数用于执行调度到主线程的重复工作。
  • 使用标准错误而不是定义自定义错误。
  • do/catch和抛出用于一次处理所有错误。

我还有最后一点:异步函数应该始终是异步的。错误的 URL 错误不应直接调用completion(_:);使用DispatchQueue.main.async确保调用在以后的运行循环中发生。

最新更新