keyNotFound (CodingKeys (stringValue: "координата", intValue: ноль) - PullRequest
0 голосов
/ 28 апреля 2019

Я создаю небольшое приложение для быстрой погоды с использованием openweatherAPI и сталкиваюсь с некоторыми проблемами, пытаясь проанализировать JSON. Я использовал следующую функцию для разбора get и парсинга json.

Ниже моя структура данных о погоде:

struct WeatherData: Codable {
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind
    let clouds: Clouds
    let dt: Int
    let sys: Sys
    let id: Int
    let name: String
    let cod: Int
}

struct Clouds: Codable {
    let all: Int
}

struct Coord: Codable {
    let lon, lat: Double
}

struct Main: Codable {
    let temp: Double
    let pressure, humidity: Int
    let tempMin, tempMax: Double

    enum CodingKeys: String, CodingKey {
        case temp, pressure, humidity
        case tempMin = "temp_min"
        case tempMax = "temp_max"
    }
}

struct Sys: Codable {
    let type, id: Int
    let message: Double
    let country: String
    let sunrise, sunset: Int
}

struct Weather: Codable {
    let id: Int
    let main, description, icon: String
}

struct Wind: Codable {
    let speed: Double
    let deg: Int
}


private func getWeatherData(url: String, parameters: [String : String]) {
    let JsonURLString:[String: Any] = ["url": WEATHER_URL, "parameters": parameters]
    print(JsonURLString)
    let urlString = JsonURLString["url"] as? String
    guard let url = URL(string: urlString!) else { return }
    URLSession.shared.dataTask(with: url) { ( data, response, err ) in
        DispatchQueue.main.sync {
            if let err = err {
                print("Failed to get data from url:", err)
                return
            }
            guard let data = data else { return }
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let city = try decoder.decode(WeatherData.self, from: data)
                self.weatherData.description = city.weather[0].description
                self.weatherData.temperature = Int(city.main.temp - 273)
                self.weatherData.city = city.name
                self.weatherData.condition = city.weather[0].id
                self.updateUIWeatherData()
            } catch {
                print(error)
                self.cityLabel.text = "Connection issues"
            }
        }
    }.resume()
}

Я получаю следующую ошибку:

  longitude = -0.1337, latitude = 51.50998
 ["parameters": ["lat": "51.50998", "long": "-0.1337", "appid":    "xxxxxxxxxxxxxxxxxx"], "url":   "https://api.openweathermap.org/data/2.5/weather"]
  keyNotFound(CodingKeys(stringValue: "coord", intValue: nil),    Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated     with key CodingKeys(stringValue: \"coord\", intValue: nil) (\"coord\").",    underlyingError: nil))

Я посмотрел на следующий пример и не вижу, как это применимо. Любая помощь будет оценена.

Значок не появляется. Вот моя модель:

import UIKit

class WeatherDataModel {

//Declare your model variables here
var temperature: Int = 0
var condition: Int = 0
var city: String = ""
var weatherIconName = ""
var description: String = ""

//This method turns a condition code into the name of the weather condition image

func updateWeatherIcon(condition: Int) -> String {

switch (condition) {

    case 0...300 :
        return "tstorm1"

    case 301...500 :
        return "light_rain"

    case 501...600 :
        return "shower3"

    case 601...700 :
        return "snow4"

    case 701...771 :
        return "fog"

    case 772...799 :
        return "tstorm3"

    case 800 :
        return "sunny"

    case 801...804 :
        return "cloudy2"

    case 900...903, 905...1000  :
        return "tstorm3"

    case 903 :
        return "snow5"

    case 904 :
        return "sunny"

    default :
        return "dunno"
    }

   }
 }

Я добавил свои собственные значки. Я добавил это в блок do catch.

do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let city = try decoder.decode(WeatherData.self, from: data)
                print(city)
                self.weatherData.description = city.weather[0].description
                self.weatherData.temperature = Int(city.main.temp - 273)
                self.weatherData.city = city.name
                self.weatherData.condition = city.weather[0].id
                self.weatherData.weatherIconName = WeatherDataModel.updateWeatherIcon(self.weatherData.condition)
                self.updateUIWeatherData()
            } catch {
                print(error)
                self.cityLabel.text = "Connection issues"
            }

Ошибка Я получаю эту ошибку сейчас:

Instance member 'updateWeatherIcon' cannot be used on type 'WeatherDataModel'; did you mean to use a value of this type instead?

1 Ответ

1 голос
/ 28 апреля 2019

Вы создаете только URL-адрес openweathermap, но игнорируете параметры.

Используйте что-то вроде этого, например URLComponents и URLQueryItem, чтобы правильно построить запрос URL

private func getWeatherData(parameters: [String : String]) {
    guard let lat = parameters["lat"], 
          let long = parameters["long"],
          let appID = parameters["appid"] else { print("Invalid parameters"); return } 
    var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather")!
    let queryItems = [URLQueryItem(name: "lat", value: lat),
                      URLQueryItem(name: "lon", value: long),
                      URLQueryItem(name: "appid", value: appID)]
    urlComponents.queryItems = queryItems

    guard let url = urlComponents.url else { return }
    URLSession.shared.dataTask(with: url) { ( data, response, err ) in
        DispatchQueue.main.async { // never, never, never sync !!
            if let err = err {
                print("Failed to get data from url:", err)
                return
            }
            guard let data = data else { return }
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let city = try decoder.decode(WeatherData.self, from: data)
                print(city)
                self.weatherData.description = city.weather[0].description
                self.weatherData.temperature = Int(city.main.temp - 273)
                self.weatherData.city = city.name
                self.weatherData.condition = city.weather[0].id
                self.updateUIWeatherData()
            } catch {
                print(error)
                self.cityLabel.text = "Connection issues"
            }
        }
        }.resume()
}

и передать только

["lat": "51.50998", "long": "-0.1337", "appid": "xxxxxxxxxxxxxxxxxx"]

в качестве параметров.

...