keyNotFound(CodingKeys(stringValue:“ coord”,intValue:nil)

时间:2019-04-28 14:39:16

标签: swift openweathermap decodable

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

我查看了以下example,但看不到如何应用。任何帮助将不胜感激。

图标未出现。这是我的模型:

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 个答案:

答案 0 :(得分:1)

您仅创建openweathermap URL,但是忽略了参数。

例如使用URLComponentsURLQueryItem这样的东西来正确构建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"]

作为参数。