swift - 为什么这个 JSON 解码会使我的应用程序崩溃?
问题描述
我有这个由键盘输入触发的功能,如果输入正确,应用程序会正确运行;如果不是,应用程序本质上会冻结并且无法更改键盘输入(需要重新启动)。
这就是所谓的函数:
override func viewDidLoad() {
super.viewDidLoad()
makeGetCall()
repeat{
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
}while !done
被调用的函数:
func makeGetCall() {
let jsonUrlString = "http://api.openweathermap.org/data/2.5/weather?q=" + city + ",us&appid=f0d10597634568abee813f68138452fd&units=imperial"
guard let url = URL(string: jsonUrlString) else {
print("Error: cannot create URL")
return
}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {
print("Error: did not receive data")
return
}
do {
self.document = try JSONDecoder().decode(WeatherDocument.self, from: data)
self.done = true
print(self.document!)
print("========================INIT===============================")
print(self.document?.main?.temp! ?? "No temp")
print(self.document?.name! ?? "No temp")
print(self.document?.weather![0].description ?? "No info")
print(self.document?.wind?.speed ?? "No wind")
print("==========================END===============================")
print(self.document?.weather![0].main ?? "No main info")
} catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()
}
任何想法为什么会发生这种情况?
这是控制台中显示的错误消息:
“错误序列化 json: typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "cod", intValue: nil)], debugDescription: "预期解码 Double 但找到了一个字符串/数据。" ,基础错误:无)“
天气文件
struct WeatherDocument: Decodable {
let coord: Coordinates?
let weather: [Weather]?
let base: String?
let main: Main?
let visibility: Double?
let wind: Wind?
let clouds: Clouds?
let dt: Double?
let sys: Sys?
let id: Double?
let name: String?
let cod: Double?
}
现在应用程序在我所做的以下语句处执行断点:
let tempe = (self.document?.main?.temp!)!
let humiditye = (self.document?.main?.humidity!)!
let pressurePow = (self.document?.main?.pressure!)! * 0.295300 * 0.10
let tempeMax = (self.document?.main?.temp_max!)! - 273.15
let tempeMin = (self.document?.main?.temp_min!)! - 273.15
//let clouding = (self.precip?.threeHours!)!
let name = (self.document?.name!)!
为什么完成处理程序有这个问题?
解决方案
两个问题:
该错误清楚地表明类型
cod
是字符串。您可以将所有结构成员声明为非可选的。Openweathermap 发送可靠的数据。只有少数值(例如Rain
在预测 API 中)是可选的let cod : String
永远不要使用这样的重复循环。你阻塞线程。使用完成处理程序。强烈建议使用
URLComponents
隐式添加百分比编码。var city = "New York,us" let apiKey = <your api key> ... func makeGetCall(completion: @escaping (WeatherDocument?, Error?)->Void) { var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather")! let queryItems = [URLQueryItem(name: "q", value: city), URLQueryItem(name: "appid", value: apiKey), URLQueryItem(name: "units", value: "imperial")] guard let url = urlComponents.url else { print("Error: cannot create URL") return } URLSession.shared.dataTask(with: url) { (data, response, err) in guard let data = data else { print("Error: did not receive data") completion(nil, error!) } do { let document = try JSONDecoder().decode(WeatherDocument.self, from: data) print(document) print("========================INIT===============================") print(document.main.temp) // main and temp can be non-optional print(document.name) // name can be non-optional print(document.weather[0].description) // weather and description can be non-optional print(document.wind.speed) // wind and speed can be non-optional print("==========================END===============================") print(document.weather[0].main) // weather and main can be non-optional completion(document, nil) } catch { print("Error serializing json:", error) completion(nil, error) } }.resume() }
并称之为
makeGetCall() { doc, error in if let doc = doc { self.document = doc } else { print(error!) } }
PS:您混淆了预测和天气API。您的结构属于预测 API -cod
实际上在哪里Int
- 但代码(和解码错误)属于天气 API。问题中的结构永远不会与此代码/ URL 一起使用。
推荐阅读
- java - 如何通过服务本身内的通知调用方法?
- javascript - 按顺序执行许多承诺(概念)
- jquery - Bootstrap折叠导航栏切换不起作用
- python - 使用 Pandas 读取和传递 Excel 文件名
- jenkins - Blue Ocean - “存储库 URL - 请输入有效的 URL”错误
- maven - 在 Maven 可选依赖项中指定版本
- python - 如何在numpy ndarray中将具有相同行和列的值设置为零?
- json - 将“lang”查询参数添加到 wordpress rest api 调用删除 _embedded
- docker - 像注册表一样公开本地 docker 映像的快速简便方法?
- postgresql - 如何在 postgresql 中为更新添加默认值?