【问题标题】:Catching json error "wrong latitude and longitude" in Swift / SwiftUI在 Swift / SwiftUI 中捕获 json 错误“错误的纬度和经度”
【发布时间】:2021-11-22 23:25:02
【问题描述】:

我正在使用 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)
}

【问题讨论】:

  • 那个叫'T.self'的家伙是哪里来的?
  • 没人知道T家伙处理什么样的数据。
  • @ElTomato 我编辑了我的问题
  • 您要访问哪个 openweathermap api?作为响应的一部分,我只是看不到Forecast json 的位置。

标签: json swift error-handling


【解决方案1】:

在 Swift 中一个流畅的方法是使用带有关联值的枚举。您会得到一个包含天气数据的 success 案例和一个带有错误消息的 failure 案例。

枚举首先将cod 解码为Int。如果成功则解码天气数据,否则codString 并解码错误数据。

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)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 2012-12-30
    • 2023-03-22
    相关资源
    最近更新 更多