Reputation: 322
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
Reputation: 99
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
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
Reputation: 535900
Your WeatherViewModel property city
is a String, but there is no "city"
key in your JSON.
Upvotes: 2