Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am building a small swift weather app using the openweatherAPI and I am running into some issues trying to parse the JSON. I have used the following function to parse the get and parse the json.

Below is my weather data struct:

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

The exact error I am getting is the following:

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

I have looked at the following example and don't see how this would apply. Any help would be appreciated.

Icon is not appearing. Here is my model:

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

   }
 }

I have added my own icons. I have added this in the do catch block.

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

The error I am getting this error now:

Instance member 'updateWeatherIcon' cannot be used on type 'WeatherDataModel'; did you mean to use a value of this type instead?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
350 views
Welcome To Ask or Share your Answers For Others

1 Answer

You are creating only the openweathermap URL but you ignore the parameters.

Use something like this for example URLComponents and URLQueryItem to build the URL query properly

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

and pass only

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

as parameters.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...