Swift调用日出日落API时JSONDecoder解码失败该如何解决?
问题排查及修复方案
你将getData函数移出ViewController的操作不影响代码逻辑,不会导致解码失败,无需回退该修改。本次解码失败的核心原因如下:
1. 请求URL参数错误
你当前的请求URL结尾为不完整的&form,属于无效参数,会导致接口返回结构异常。正确的参数应为formatted,该参数控制返回值格式:
- 若传
formatted=0:day_length返回秒级数值(对应你模型里的Int类型,符合你的需求) - 若传
formatted=1(默认值):day_length返回HH:MM:SS格式字符串,会和你定义的Int类型冲突,直接触发解码失败
修正后的合法URL为:https://api.sunrise-sunset.org/json?date=2020-01-01&lat=-74.060&lng=40.7128&formatted=0
2. Swift Playground异步执行配置缺失
Playground默认执行完同步代码后会直接终止进程,不会等待URLSession的异步回调返回,所以哪怕代码逻辑正确也可能看不到返回结果,需要在Playground开头添加配置允许无限期执行:
import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true
3. 可选优化点(避免崩溃)
你当前对URL做了强制解包,若URL构造失败会直接触发崩溃,建议替换为可选绑定判断:
guard let requestUrl = URL(string: url) else { print("URL构造失败") return } let task = URLSession.shared.dataTask(with: requestUrl, completionHandler: { ... })
另外解码报错时建议打印完整的error对象而不是localizedDescription,可以直接看到字段不匹配等具体错误原因,方便排查:
catch { print("解码失败: \(error)") }
完整可运行代码示例
import UIKit import PlaygroundSupport // 允许Playground等待异步任务执行 PlaygroundPage.current.needsIndefiniteExecution = true // 模型定义 struct Response: Codable { let results: MyResult let status: String } struct MyResult: Codable { let sunrise: String let sunset: String let solar_noon: String let day_length: Int let civil_twilight_begin: String let nautical_twilight_begin: String let nautical_twilight_end: String let astronomical_twilight_begin: String let astronomical_twilight_end: String } // 请求逻辑 let url = "https://api.sunrise-sunset.org/json?date=2020-01-01&lat=-74.060&lng=40.7128&formatted=0" getData(from: url) private func getData(from url: String) { guard let requestUrl = URL(string: url) else { print("URL构造错误") return } let task = URLSession.shared.dataTask(with: requestUrl, completionHandler: { data, response, error in guard let data = data, error == nil else { print("请求出错: \(error?.localizedDescription ?? "未知错误")") return } do { let result = try JSONDecoder().decode(Response.self, from: data) print("状态: \(result.status)") print("日出时间: \(result.results.sunrise)") print("昼长: \(result.results.day_length)秒") } catch { print("解码失败, 详细错误: \(error)") } }) task.resume() }
内容的提问来源于stack exchange,提问作者John Sorensen
相关产品推荐
相关产品推荐

