Reputation: 31
I need to do Sunset Sunrise App, and this is my code. But I have this error:
Error serializing json: keyNotFound(Sunrise_Sunset.SunPosition.Results.(CodingKeys in _B4291256871B16D8D013EC8806040532).sunrise, Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key sunrise (\"sunrise\").", underlyingError: nil))
And I don't understand how to fix it. Maybe someone had this problem. I will be grateful for any help) This is the API, which I have: https://sunrise-sunset.org/api
struct SunPosition: Codable {
struct Results: Codable {
let sunrise: String
let sunset: String
let solarNoon: String
let dayLenght: String
let civilTwilightBegin: String
let civilTwilightEnd: String
let nauticalTwilightBegin: String
let nauticalTwilightEnd: String
let astronomicalTwilightBegin: String
let astronomicalTwilightEnd: String
enum CodingKey:String, Swift.CodingKey {
case sunrise = "sunrise"
case sunset = "sunset"
case solarNoon = "solar_noon"
case dayLenght = "day_length"
case civilTwilightBegin = "civil_twilight_begin"
case civilTwilightEnd = "civil_twilight_end"
case nauticalTwilightBegin = "nautical_twilight_begin"
case nauticalTwilightEnd = "nautical_twilight_end"
case astronomicalTwilightBegin = "astronomical_twilight_begin"
case astronomicalTwilightEnd = "astronomical_twilight_end"
}
}
}
extension SunPosition.Results {
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
sunrise = try values.decode(String.self, forKey: .sunrise)
sunset = try values.decode(String.self, forKey: .sunset)
solarNoon = try values.decode(String.self, forKey: .solarNoon)
dayLenght = try values.decode(String.self, forKey: .dayLenght)
civilTwilightBegin = try values.decode(String.self, forKey: .civilTwilightBegin)
civilTwilightEnd = try values.decode(String.self, forKey: .civilTwilightEnd)
nauticalTwilightBegin = try values.decode(String.self, forKey: .nauticalTwilightBegin)
nauticalTwilightEnd = try values.decode(String.self, forKey: .nauticalTwilightEnd)
astronomicalTwilightBegin = try values.decode(String.self, forKey: .astronomicalTwilightBegin)
astronomicalTwilightEnd = try values.decode(String.self, forKey: .astronomicalTwilightEnd)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let jsonUrlString = "https://api.sunrise-sunset.org/json?lat=36.7201600&lng=-4.4203400"
guard let url = URL(string: jsonUrlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do {
let sunPosition = try JSONDecoder().decode(SunPosition.Results.self, from: data)
print(sunPosition)
}catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()
}
}
Upvotes: 3
Views: 9314
Reputation: 14063
To rule it out, if for some reason your endpoint is returning an error message or nil data, you'll get this error.
Upvotes: 1
Reputation: 285220
Four issues:
let results : Results
in the SunPosition
struct.private enum CodingKeys: String, CodingKey
rather than enum CodingKey :String, Swift.CodingKey
, note the singular / plural difference, the private
attribute is recommended but does not cause the issue.JSONDecoder().decode(SunPosition.self, from: data)
rather than JSONDecoder().decode(SunPosition.Results.self, from: data)
.results
you have to print(sunPosition.results)
.Three notes:
Add &formatted=0
to the URL and set the dateDecodingStrategy
of the decoder to .iso8601
to get Date
objects. Change the type of all date related properties from String
to Date
and the type of dayLenght
from String
to TimeInterval
. To change dateDecodingStrategy
write
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let sunPosition = try decoder.decode(SunPosition.self ...
I recommend to handle the status
, too. Add this in the SunPosition
struct
let status : String
var success : Bool { return status == "OK" }
Upvotes: 8