在 Swift / SwiftUI 中捕获 json 错误"wrong latitude and longitude"



我使用openweathermap api。当输入错误的api键或输入错误的经纬度坐标时,我得到如下错误。我用自己的方法向用户显示这个错误,但我想用更好的方法。我不喜欢我自己的代码。我想学得更好。:)

JSON错误:

{"cod":"400","message":"wrong latitude"}

T模型:

struct Forecast: Codable {
let daily: [Daily]
}
struct Daily: Codable {
let dt: Date
let temp: Temp
let humidity: Int
let weather: [Weather]
let clouds: Int
let pop: Double
}
struct Temp: Codable {
let min: Double
let max: Double
}
struct Weather: Codable {
let id: Int
let main: String
let description: String
let icon: String
}

我的代码:

功能1:

如果在第一个函数中输入了错误的纬度或经度,则捕获错误,因为它无法解码传入的数据。由于json发送的错误无法解码,我编写了一个不同的函数(getApiError(url: url) { }),并在该函数中解码json中的错误。

func getForecast<T: Decodable>(api url: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping(Result<T, ApiError>) -> Void) {
guard let url = URL(string: url) else {
completion(.failure(.error("Hatalı URL")))
return
}
let request = URLRequest(url: url)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
URLSession.shared.dataTaskPublisher(for: request)
.map({ $0.data })
.decode(type: T.self, decoder: decoder)
.receive(on: DispatchQueue.main)
.sink { taskCompletion in
switch taskCompletion {

case .finished:
return
case .failure(_):
here ->   self.getApiError(url: url) { (result: Result<ApiErrorMessage, ApiError>) in
switch result {
case .success(let item):
completion(.failure(.error("Api Key Hatası. (item.cod)n(item.message)")))
case .failure(_):
completion(.failure(.error("Kod çözme hatası.")))
}
}
}
} receiveValue: { decodeData in
completion(.success(decodeData))
}
.store(in: &anyCancellable)
}

功能2:

在这个函数中,我从json解码错误。你觉得我做得对吗?我不确定。

func getApiError(url request: URL, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping(Result<ApiErrorMessage, ApiError>) -> Void) {
let request = URLRequest(url: request)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
URLSession.shared.dataTaskPublisher(for: request)
.map({ $0.data })
.decode(type: ApiErrorMessage.self, decoder: decoder)
.receive(on: DispatchQueue.main)
.sink { taskCompletion in
switch taskCompletion {
case .finished:
return
case .failure(let decodingError):
completion(.failure(.error("Kod çözme hatası. (decodingError.localizedDescription)")))
}
} receiveValue: { decodeData in
completion(.success(decodeData))
}
.store(in: &anyCancellable)
}

在Swift中,一个比较流畅的方法是使用带有关联值的enum。您将得到包含天气数据的success大小写和包含错误消息的failure大小写。

枚举首先将cod解码为Int。如果此操作成功,则对天气数据进行解码,如果不是cod,则为String,并对错误数据进行解码。

WeatherData替换为根对象名称并解码Response.self。它可以类似于Result类型

使用
enum Response : Decodable {
case success(WeatherData), failure(ErrorData)

private enum CodingKeys : String, CodingKey { case cod }

init(from decoder : Decoder) throws {
let containar = try decoder.container(keyedBy: CodingKeys.self)
let singleContainer = try decoder.singleValueContainer()
do {
let _ = try containar.decode(Int.self, forKey: .cod)
self = .success(try singleContainer.decode(WeatherData.self))
} catch DecodingError.typeMismatch {
self = .failure(try singleContainer.decode(ErrorData.self))
}
}
}
struct ErrorData : Decodable {
let cod, message: String
}

调用方switch基于JSONDecoder

的结果
switch result {
case .success(let weatherData): print(weatherData)
case .success(let error): print(error.message)
}

最新更新