syds
syds

Reputation: 322

Swift: JSONDecoder returning nil from API

currently working through an app that gets and decodes data from OpenWeatherMap API, currently I've got everything working except getting the decoder to return something. Currently, the decoder is returning nil, however, I am getting bytes of data from the API call. I am not exactly sure what could be the issue. I've got the ViewModel struct set up in terms of hierarchy. The OPW API JSON data seems to be in the format of a dictionary key:value pair collection type, keys are enclosed in quotes, could it be that my decoder isn't finding the necessary information because of the quotation marks?

Getting and Decoding the API call...

@IBAction func saveCityButtonPressed() {

    if let city = cityNameTextField.text {
        let weatherURL = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(city)&APPID=8bad8461edbaf3ff50aa2f2fd8ad8a71&units=imperial")!

        let weatherResource = Resource<WeatherViewModel>(url: weatherURL) { data in
            let weatherVM = try? JSONDecoder().decode(WeatherViewModel.self, from: data)
            return weatherVM
        }
        Webservice().load(resource: weatherResource) { result in
        }
    }
}

ViewModel

struct WeatherListViewModel {
private var weatherViewModels = [WeatherViewModel]()
}

struct WeatherViewModel: Decodable {
let name: String
let main: TemperatureViewModel
}

struct TemperatureViewModel: Decodable {
let temp: Double
let temp_min: Double
let temp_max: Double
}

Example of JSON data:

{
    "coord":{
       "lon":-0.13,
       "lat":51.51
    },
    "weather":[
        {
             "id":300,
             "main":"Drizzle",
             "description":"light intensity drizzle","icon":"09d"
        }
    ],
    "base":"stations",
    "main":{
        "temp":280.32,
        "pressure":1012,
        "humidity":81,
        "temp_min":279.15,
        "temp_max":281.15
     },
     "visibility":10000,
     "wind":{
         "speed":4.1,
         "deg":80
     },
     "clouds":{
         "all":90
     },
     "dt":1485789600,
     "sys":{
         "type":1,
         "id":5091,
         "message":0.0103,
         "country":"GB",
         "sunrise":1485762037,
         "sunset":1485794875
     },
     "id":2643743,
     "name":"London",
     "cod":200
 }

Upvotes: 5

Views: 7794

Answers (3)

Why do we get nil value, when decoding the value?

Reasons:
The response parameter may be the first letter as capital.

Solution:
The coding keys concept is to out to nil value.

Example:

struct Example{
var a: string
var b: string

enum Codingkeys: String,CodingKey{
case a = "a"
case b = "b"
}
}

Upvotes: -1

grow4gaurav
grow4gaurav

Reputation: 3305

By making the result of JSONDecoder().decode an optional (try?), you are ensuring that you get nil if the decoding goes wrong. You can catch decoding related issues quickly by implementing proper catch blocks. E.g.:

do {
    let decoder = JSONDecoder()
    let messages = try decoder.decode(WeatherViewModel.self, from: data)
    print(messages as Any)
} catch DecodingError.dataCorrupted(let context) {
    print(context)
} catch DecodingError.keyNotFound(let key, let context) {
    print("Key '\(key)' not found:", context.debugDescription)
    print("codingPath:", context.codingPath)
} catch DecodingError.valueNotFound(let value, let context) {
    print("Value '\(value)' not found:", context.debugDescription)
    print("codingPath:", context.codingPath)
} catch DecodingError.typeMismatch(let type, let context) {
    print("Type '\(type)' mismatch:", context.debugDescription)
    print("codingPath:", context.codingPath)
} catch {
    print("error: ", error)
}

Not a direct answer to your question, but surely will reduce other's time to understand which part of decoding is going wrong.

Upvotes: 25

matt
matt

Reputation: 535900

Your WeatherViewModel property city is a String, but there is no "city" key in your JSON.

Upvotes: 2

Related Questions