我正在寻找一些帮助与Swift项目工作。我正在构建一个从API中提取航空天气数据的应用程序,这种情况很常见:
用户需要来自机场气象站的数据,目前的报告说:
用户需要来自机场气象站的数据,KJAX -当前的报告说:
<代码>H 119少数云2400英尺<代码>H 220<代码>F 221
在这个简单的例子中,您可能会注意到,在本报告所述期间,没有为KJAX提供任何阵风数据,也没有为K民建联指定“特殊天气”(即雨、雾、雾)。我的应用程序需要能够处理“零”或不提供数据,而不只是告诉我有一个valueNotFound或索引超出范围。
下面是API:https://avwx.docs.apiary.io/#reference/0/metar/get-metar-report
这是我的代码:
import Foundation
struct WeatherManager {
let weatherURL = "https://avwx.rest/api/metar/"
func fetchWeather (stationICAO: String) {
let urlString = "\(weatherURL)\(stationICAO)?token=OVi45FiTDo1LmyodShfOfoizNe5m9wyuO6Mkc95AN-c"
performRequest(urlString: urlString)
}
func performRequest (urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let safeData = data {
self.parseJSON(weatherData: safeData)
}
}
task.resume()
print(urlString)
}
}
func parseJSON(weatherData: Data) {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
let lowCloudsType = decodedData.clouds[0].type
let midCloudsType = decodedData.clouds[1].type
let highCloudsType = decodedData.clouds[2].type
let lowCloudsAlt = decodedData.clouds[0].altitude
let midCloudsAlt = decodedData.clouds[1].altitude
let highCloudsAlt = decodedData.clouds[2].altitude
let reportingStationVar = decodedData.station
let windGustValue = decodedData.wind_gust.value
let windSpeedValue = decodedData.wind_speed.value
let windDirectionValue = decodedData.wind_direction.value
let visibilityValue = decodedData.visibility.value
let flightRulesValue = decodedData.flight_rules
let weather = WeatherModel(lowestCloudsType: lowCloudsType, lowestCloudsAlt: lowCloudsAlt, middleCloudsType: midCloudsType, middleCloudsAlt: midCloudsAlt, highestCloudsType: highCloudsType, highestCloudsAlt: highCloudsAlt, reportingStation: reportingStationVar, windGust: windGustValue, windSpeed: windSpeedValue, windDirection: windDirectionValue, visibility: visibilityValue, flightRules: flightRulesValue)
print(weather.flightConditions)
} catch {
print(error)
}
}
}import Foundation
struct WeatherModel {
let lowestCloudsType: String
let lowestCloudsAlt: Int
let middleCloudsType: String
let middleCloudsAlt: Int
let highestCloudsType: String
let highestCloudsAlt: Int
let reportingStation: String
let windGust: Int
let windSpeed: Int
let windDirection: Int
let visibility: Int
let flightRules: String
var flightConditions: String {
switch flightRules {
case "VFR":
return "green"
case "MVFR":
return "blue"
case "IFR":
return "red"
case "LIFR":
return "purple"
default:
return "gray"
}
}
}最后一个:
import Foundation
struct WeatherData: Decodable {
let clouds: [Clouds]
let flight_rules: String
let remarks: String
let wind_speed: WindSpeed
let wind_gust: WindGust
let wind_direction: WindDirection
let visibility: Visibility
let station: String
}
struct Clouds: Decodable {
let type: String
let altitude: Int
}
struct WindSpeed: Decodable {
let value: Int
}
struct WindGust: Decodable {
let value: Int
}
struct WindDirection: Decodable {
let value: Int
}
struct Visibility: Decodable {
let value: Int
}根据我所玩的内容,当我进入一个没有所有给定信息的站点时,我会得到以下错误,如果气象服务报告了这些信息,我需要能够向用户展示这些信息。
2020-09-22 02:47:58.930421-0400 AvWx Pro[66612:4483807] libMobileGestalt MobileGestaltCache.c:38: No persisted cache on this platform.
KDAB
https://avwx.rest/api/metar/KDAB?token=(mySecretToken)
2020-09-22 02:48:02.943231-0400 AvWx Pro[66612:4483809] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
valueNotFound(Swift.KeyedDecodingContainer<AvWx_Pro.WindGust.(unknown context at $1053fb3b8).CodingKeys>,
Swift.DecodingError.Context(codingPath:
[CodingKeys(stringValue: "wind_gust", intValue: nil)],
debugDescription: "Cannot get keyed decoding container
-- found null value instead.", underlyingError: nil))当我使用一个没有报告所有三个可能的云层的机场时,会出现另一个错误:
2020-09-22 03:06:02.398628-0400 AvWx Pro[66736:4497432] libMobileGestalt MobileGestaltCache.c:38: No persisted cache on this platform.
KJAX
https://avwx.rest/api/metar/KJAX?token=(mySecretKey)
2020-09-22 03:06:07.955064-0400 AvWx Pro[66736:4497429] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Fatal error: Index out of range: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1200.2.22.2/swift/stdlib/public/core/ContiguousArrayBuffer.swift, line 444
2020-09-22 03:06:08.908826-0400 AvWx Pro[66736:4497429] Fatal error: Index out of range: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1200.2.22.2/swift/stdlib/public/core/ContiguousArrayBuffer.swift, line 444
(lldb) 我花了几个小时来尝试我在网上找到的各种解决方案,包括使用选项和强制展开,使用守护let,使用if let,以及一些其他的解决方案。我现在很迷茫。
我是新的这个平台(作为海报),并将真正感谢任何洞察力任何人都可以提供!谢谢你提前帮忙。
发布于 2020-09-22 09:35:57
为了在解码json时避免崩溃,您应该对结构进行正确的配置,并在访问值之前检查字段:
CodingKeys(stringValue:"wind_gust",intValue: nil),debugDescription:“无法得到键控解码容器--找到空值。”,underlyingError: nil)
wind_gust可以是空的,因此应该使其成为可选的:
如果一个字段在响应中可以是空的或空的,那么应该使它在您的结构中是可选的,例如:
struct WeatherData: Decodable {
...
let wind_gust: WindGust?
...
}然后,在代码中,如果存在wind_gust,只需使用可选绑定提取值:
if let value = decodedData.wind_gust?.value {
print(value)
}致命错误:超出范围的索引
在访问项之前,必须始终检查数组的边界,例如:
let clouds = decodedData.clouds
let lowCloudsType = clouds.count > 0 ? clouds[0].type : nil
let midCloudsType = clouds.count > 1 ? clouds[1].type : nil
let highCloudsType = clouds.count > 2 ? clouds[2].type : nil
if let low = lowCloudsType, let mid = midCloudsType, let high = highCloudsType {
print(low)
print(mid)
print(high)
}发布于 2020-09-22 09:06:57
答案是使用选项
考虑下面的操场示例,年龄和位置属性是可选的,JSON中缺少location属性。
import Foundation
struct TestModel: Decodable {
let name: String
let age: Int?
let location: String?
enum CodingKeys: String, CodingKey {
case name
case age
case location
}
}
let jsonData = """
{
"name": "John Smith",
"age": 28
}
""".data(using: .utf8)!
let result = try JSONDecoder().decode(TestModel.self, from: jsonData)
print(result)输出
TestModel(姓名:"John“,年龄:可选(28),地点:0)
https://stackoverflow.com/questions/64004687
复制相似问题