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()
}
}
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" }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With