在字典中解码字典 - JSON/Swift
Decoding a Dictionary Inside a Dictionary - JSON/Swift
我有一个 JSON 文件,其结构如下:
"forecast": [
{
"altimeter": "",
"clouds": [
{
"repr": "OVC025",
"type": "OVC",
"altitude": 25,
"modifier": null,
"direction": null
}
],
"flight_rules": "MVFR",
"other": [],
"sanitized": "0318/0424 34017G26KT P6SM -RA OVC025",
"visibility": {
"repr": "P6",
"value": null,
"spoken": "greater than six"
},
"wind_direction": {
"repr": "340",
"value": 340,
"spoken": "three four zero"
}
And so on....
我正在尝试使用 DispatchQueue 访问信息并更新 UI,但无法弄清楚如何从 forecast: clouds: repr(或任何其他类似的嵌套)中提取数据。我可以成功地提取数据,例如:forecast: raw。我尝试了第一个没有嵌套的结构,但是没有用(正如预期的那样,数据是里面的另一个索引)。
我的解码文件是:
//
// TAFData.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/24/20.
//
import Foundation
struct TAFDatas: Codable {
let flight_rules: String?
let time: TimeTAF?
let station: String?
let raw: String?
let forecast: [ForecastTAF?]
let end_time: ?
let wind_gust: ?
}
struct ForecastTAF: Codable {
let raw: String?
struct CloudsTAF: Codable {
let type: String
let altitude: Int
}
struct endTimeTAF: Codable {
let repr: String
}
struct WindSpeedTAF: Codable {
let value: Int
}
struct WindGustTAF: Codable {
let value: Int
}
struct WindDirectionTAF: Codable {
let repr: String
}
struct VisibilityTAF: Codable {
let repr: String
}
struct WxcodesTAF: Codable {
let value: String
}
struct StartTimeTAF: Codable {
let repr: String
}
struct EndTimeTAF: Codable {
let repr: String
}
}
struct TimeTAF: Codable {
let repr: String
}
我的解析文件是:
//
// TAFManager.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/24/20.
//
import Foundation
protocol TAFManagerDelegate : class {
func didUpdateTAF(_ weatherManager: TAFManager, weatherTAF: TAFModel)
func didFailWithErrorTAF(error: Error)
}
struct TAFManager {
let TAFURL = "https://avwx.rest/api/taf/"
weak var delegate : TAFManagerDelegate?
func fetchWeatherTAF (stationICAO: String) {
let TAFurlString = "\(TAFURL)\(stationICAO)?token=OVi45FiTDo1LmyodShfOfoizNe5m9wyuO6Mkc95AN-c"
performRequestTAF(with: TAFurlString)
}
func performRequestTAF (with TAFurlString: String) {
if let TAFurl = URL(string: TAFurlString) {
let session = URLSession(configuration: .default)
let taskTAF = session.dataTask(with: TAFurl) { (data, response, error) in
if error != nil {
self.delegate?.didFailWithErrorTAF(error: error!)
return
}
if let safeDataTAF = data {
if let weatherTAF = self.parseJSONTAF(safeDataTAF) {
self.delegate?.didUpdateTAF(self, weatherTAF: weatherTAF)
}
}
}
taskTAF.resume()
print(TAFurlString)
}
}
func parseJSONTAF(_ TAFData: Data) -> TAFModel? {
do {
let decoderTAF = JSONDecoder()
let decodedDataTAF = try decoderTAF.decode(TAFDatas.self, from: TAFData)
let cloudsTAF = decodedDataTAF.clouds
let wxcodesTAF = decodedDataTAF.wx_codes
let forecastTAF = decodedDataTAF.forecast
let lowCloudsTypeTAF = (cloudsTAF.count > 0 ? cloudsTAF[0]?.type : nil) ?? "N/A"
let midCloudsTypeTAF = (cloudsTAF.count > 1 ? cloudsTAF[1]?.type : nil) ?? "N/A"
let highCloudsTypeTAF = (cloudsTAF.count > 2 ? cloudsTAF[2]?.type : nil) ?? "N/A"
let lowCloudsAltTAF = (cloudsTAF.count > 0 ? cloudsTAF[0]?.altitude : nil) ?? 0
let midCloudsAltTAF = (cloudsTAF.count > 1 ? cloudsTAF[1]?.altitude : nil) ?? 0
let highCloudsAltTAF = (cloudsTAF.count > 2 ? cloudsTAF[2]?.altitude : nil) ?? 0
let reportingStationVarTAF = decodedDataTAF.station ?? "N/A"
let windGustValueTAF = decodedDataTAF.wind_gust?.value ?? 0
let windSpeedValueTAF = decodedDataTAF.wind_speed?.value ?? 0
let windDirectionValueTAF = decodedDataTAF.wind_direction?.repr ?? "N/A"
let visibilityValueTAF = decodedDataTAF.visibility?.repr ?? "N/A"
let flightRulesValueTAF = decodedDataTAF.flight_rules ?? "N/A"
let timeReportedTAF = decodedDataTAF.time?.repr ?? "N/A"
let firstWxCode1TAF = (wxcodesTAF.count > 0 ? wxcodesTAF[0]?.value : "N/A") ?? "N/A"
let startTimeTaf = decodedDataTAF.start_time?.repr ?? "N/A"
let endTimeTaf = (forecastTAF.count > 0 ? forecastTAF[0]? : nil) ?? "N/A"
let rawTAFData = (forecastTAF.count > 0 ? forecastTAF[0]?.raw : nil) ?? "N/A"
let weatherTAF = TAFModel(lowestCloudsTypeTAF: lowCloudsTypeTAF , lowestCloudsAltTAF: lowCloudsAltTAF, middleCloudsTypeTAF: midCloudsTypeTAF , middleCloudsAltTAF: midCloudsAltTAF, highestCloudsTypeTAF: highCloudsTypeTAF , highestCloudsAltTAF: highCloudsAltTAF, reportingStationTAF: reportingStationVarTAF, windGustTAF: windGustValueTAF, windSpeedTAF: windSpeedValueTAF, windDirectionTAF: windDirectionValueTAF, visibilityTAF: visibilityValueTAF, flightRulesTAF: flightRulesValueTAF, timeTAF: timeReportedTAF, startTimeTAF: startTimeTaf, endTimeTAF: endTimeTaf, firstWxCodeTAF: firstWxCode1TAF, rawTAF: rawTAFData)
delegate?.didUpdateTAF(self, weatherTAF: weatherTAF)
return weatherTAF
} catch {
delegate?.didFailWithErrorTAF(error: error)
return nil
}
}
}
我的模型文件是:
//
// WeatherModel.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/22/20.
//
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: String
let visibility: String
let flightRules: String
let time: String
let remarks: String
let altimeter: Double
let temperature: String
let dewpoint: String
let firstWxCode: String
var altToString1: String {
return String(format: "%u" + "00 ft", lowestCloudsAlt)
}
var altToString2: String {
return String(format: "%u" + "00 ft", middleCloudsAlt)
}
var altToString3: String {
return String(format: "%u" + "00 ft", highestCloudsAlt)
}
var windGustString: String {
return String(format: "%u" + "kt", windGust)
}
var windSpeedString: String {
return String(format: "%u" + "kt", windSpeed)
}
var altimeterString: String {
return String(format: "%.2f" + " inHg", altimeter as CVarArg)
}
var visUnits: String {
return visibility + " SM"
}
var degUnits: String {
return windDirection + "°"
}
var tempUnits: String {
return temperature + "°C"
}
var dewUnits: String {
return dewpoint + "°C"
}
var flightConditions: String {
switch flightRules {
case "VFR":
return "green"
case "MVFR":
return "blue"
case "IFR":
return "red"
case "LIFR":
return "purple"
default:
return "gray"
}
}
}
我认为主要的障碍是获取那些数据密钥。一旦我到了那里,希望其余的一切都会到位。非常感谢您的提前帮助,祝您今天愉快!
有评论,我的新人JSON
// MARK: - TAFData
struct TAFData: Codable {
let meta: MetaTAF?
let raw, station: String?
let time: TimeTAF?
let remarks: String?
let forecast: [ForecastTAF?]
let startTime, endTime: TimeTAF?
let maxTemp, minTemp: String?
let alts, temps: JSONNull?
enum CodingKeys: String, CodingKey {
case meta, raw, station, time, remarks, forecast
case startTime = "start_time"
case endTime = "end_time"
case maxTemp = "max_temp"
case minTemp = "min_temp"
case alts, temps, units
}
}
// MARK: - Time
struct TimeTAF: Codable {
let repr, dt: String
}
// MARK: - Forecast
struct ForecastTAF: Codable {
let altimeter: String
let clouds: [CloudTAF]
let flightRules: String
let other: [JSONAny]
let sanitized: String
let visibility, windDirection: VisibilityTAF
let windGust: VisibilityTAF?
let windSpeed: VisibilityTAF
let wxCodes: [WxCodeTAF]
let endTime: TimeTAF
let icing: [JSONAny]
let probability: JSONNull?
let raw: String
let startTime: TimeTAF
let turbulence: [JSONAny]
let type: String
let windShear: JSONNull?
let summary: String
enum CodingKeys: String, CodingKey {
case altimeter, clouds
case flightRules = "flight_rules"
case other, sanitized, visibility
case windDirection = "wind_direction"
case windGust = "wind_gust"
case windSpeed = "wind_speed"
case wxCodes = "wx_codes"
case endTime = "end_time"
case icing, probability, raw
case startTime = "start_time"
case turbulence, type
case windShear = "wind_shear"
case summary
}
}
// MARK: - Cloud
struct CloudTAF: Codable {
let repr, type: String
let altitude: Int
let modifier, direction: JSONNull?
}
// MARK: - Visibility
struct VisibilityTAF: Codable {
let repr: String
let value: Int?
let spoken: String
}
// MARK: - WxCode
struct WxCodeTAF: Codable {
let repr, value: String
}
// MARK: - Meta
struct MetaTAF: Codable {
let timestamp: String
}
// MARK: - Units
struct UnitsTAF: Codable {
let altimeter, altitude, temperature, visibility: String
let windSpeed: String
enum CodingKeys: String, CodingKey {
case altimeter, altitude, temperature, visibility
case windSpeed = "wind_speed"
}
}
// MARK: - Encode/decode helpers
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
public func hash(into hasher: inout Hasher) {
// No-op
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
class JSONCodingKey: CodingKey {
let key: String
required init?(intValue: Int) {
return nil
}
required init?(stringValue: String) {
key = stringValue
}
var intValue: Int? {
return nil
}
var stringValue: String {
return key
}
}
class JSONAny: Codable {
let value: Any
static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError {
let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny")
return DecodingError.typeMismatch(JSONAny.self, context)
}
static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError {
let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny")
return EncodingError.invalidValue(value, context)
}
static func decode(from container: SingleValueDecodingContainer) throws -> Any {
if let value = try? container.decode(Bool.self) {
return value
}
if let value = try? container.decode(Int64.self) {
return value
}
if let value = try? container.decode(Double.self) {
return value
}
if let value = try? container.decode(String.self) {
return value
}
if container.decodeNil() {
return JSONNull()
}
throw decodingError(forCodingPath: container.codingPath)
}
static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any {
if let value = try? container.decode(Bool.self) {
return value
}
if let value = try? container.decode(Int64.self) {
return value
}
if let value = try? container.decode(Double.self) {
return value
}
if let value = try? container.decode(String.self) {
return value
}
if let value = try? container.decodeNil() {
if value {
return JSONNull()
}
}
if var container = try? container.nestedUnkeyedContainer() {
return try decodeArray(from: &container)
}
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self) {
return try decodeDictionary(from: &container)
}
throw decodingError(forCodingPath: container.codingPath)
}
static func decode(from container: inout KeyedDecodingContainer<JSONCodingKey>, forKey key: JSONCodingKey) throws -> Any {
if let value = try? container.decode(Bool.self, forKey: key) {
return value
}
if let value = try? container.decode(Int64.self, forKey: key) {
return value
}
if let value = try? container.decode(Double.self, forKey: key) {
return value
}
if let value = try? container.decode(String.self, forKey: key) {
return value
}
if let value = try? container.decodeNil(forKey: key) {
if value {
return JSONNull()
}
}
if var container = try? container.nestedUnkeyedContainer(forKey: key) {
return try decodeArray(from: &container)
}
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) {
return try decodeDictionary(from: &container)
}
throw decodingError(forCodingPath: container.codingPath)
}
static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] {
var arr: [Any] = []
while !container.isAtEnd {
let value = try decode(from: &container)
arr.append(value)
}
return arr
}
static func decodeDictionary(from container: inout KeyedDecodingContainer<JSONCodingKey>) throws -> [String: Any] {
var dict = [String: Any]()
for key in container.allKeys {
let value = try decode(from: &container, forKey: key)
dict[key.stringValue] = value
}
return dict
}
static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws {
for value in array {
if let value = value as? Bool {
try container.encode(value)
} else if let value = value as? Int64 {
try container.encode(value)
} else if let value = value as? Double {
try container.encode(value)
} else if let value = value as? String {
try container.encode(value)
} else if value is JSONNull {
try container.encodeNil()
} else if let value = value as? [Any] {
var container = container.nestedUnkeyedContainer()
try encode(to: &container, array: value)
} else if let value = value as? [String: Any] {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self)
try encode(to: &container, dictionary: value)
} else {
throw encodingError(forValue: value, codingPath: container.codingPath)
}
}
}
static func encode(to container: inout KeyedEncodingContainer<JSONCodingKey>, dictionary: [String: Any]) throws {
for (key, value) in dictionary {
let key = JSONCodingKey(stringValue: key)!
if let value = value as? Bool {
try container.encode(value, forKey: key)
} else if let value = value as? Int64 {
try container.encode(value, forKey: key)
} else if let value = value as? Double {
try container.encode(value, forKey: key)
} else if let value = value as? String {
try container.encode(value, forKey: key)
} else if value is JSONNull {
try container.encodeNil(forKey: key)
} else if let value = value as? [Any] {
var container = container.nestedUnkeyedContainer(forKey: key)
try encode(to: &container, array: value)
} else if let value = value as? [String: Any] {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key)
try encode(to: &container, dictionary: value)
} else {
throw encodingError(forValue: value, codingPath: container.codingPath)
}
}
}
static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws {
if let value = value as? Bool {
try container.encode(value)
} else if let value = value as? Int64 {
try container.encode(value)
} else if let value = value as? Double {
try container.encode(value)
} else if let value = value as? String {
try container.encode(value)
} else if value is JSONNull {
try container.encodeNil()
} else {
throw encodingError(forValue: value, codingPath: container.codingPath)
}
}
public required init(from decoder: Decoder) throws {
if var arrayContainer = try? decoder.unkeyedContainer() {
self.value = try JSONAny.decodeArray(from: &arrayContainer)
} else if var container = try? decoder.container(keyedBy: JSONCodingKey.self) {
self.value = try JSONAny.decodeDictionary(from: &container)
} else {
let container = try decoder.singleValueContainer()
self.value = try JSONAny.decode(from: container)
}
}
public func encode(to encoder: Encoder) throws {
if let arr = self.value as? [Any] {
var container = encoder.unkeyedContainer()
try JSONAny.encode(to: &container, array: arr)
} else if let dict = self.value as? [String: Any] {
var container = encoder.container(keyedBy: JSONCodingKey.self)
try JSONAny.encode(to: &container, dictionary: dict)
} else {
var container = encoder.singleValueContainer()
try JSONAny.encode(to: &container, value: self.value)
}
}
}
我可能会使用不同的模型,因为您当前的模型不支持与 JSON:
相同的格式
struct Forecast: Codable {
let altimeter: String
let clouds: [Cloud]
let flightRules: String
let other: [JSONAny]
let sanitized: String
let visibility, windDirection: Visibility
enum CodingKeys: String, CodingKey {
case altimeter, clouds
case flightRules = "flight_rules"
case other, sanitized, visibility
case windDirection = "wind_direction"
}
}
// MARK: - Cloud
struct Cloud: Codable {
let repr, type: String
let altitude: Int
}
// MARK: - Visibility
struct Visibility: Codable {
let repr: String
let value: Int?
let spoken: String
}
这样你就可以使用:
if let cloud = forecast.clouds.first() {
let repr = cloud.repr
.. Your logic
}
我的模型中可能缺少一些东西,但你应该有一个想法
我有一个 JSON 文件,其结构如下:
"forecast": [
{
"altimeter": "",
"clouds": [
{
"repr": "OVC025",
"type": "OVC",
"altitude": 25,
"modifier": null,
"direction": null
}
],
"flight_rules": "MVFR",
"other": [],
"sanitized": "0318/0424 34017G26KT P6SM -RA OVC025",
"visibility": {
"repr": "P6",
"value": null,
"spoken": "greater than six"
},
"wind_direction": {
"repr": "340",
"value": 340,
"spoken": "three four zero"
}
And so on....
我正在尝试使用 DispatchQueue 访问信息并更新 UI,但无法弄清楚如何从 forecast: clouds: repr(或任何其他类似的嵌套)中提取数据。我可以成功地提取数据,例如:forecast: raw。我尝试了第一个没有嵌套的结构,但是没有用(正如预期的那样,数据是里面的另一个索引)。
我的解码文件是:
//
// TAFData.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/24/20.
//
import Foundation
struct TAFDatas: Codable {
let flight_rules: String?
let time: TimeTAF?
let station: String?
let raw: String?
let forecast: [ForecastTAF?]
let end_time: ?
let wind_gust: ?
}
struct ForecastTAF: Codable {
let raw: String?
struct CloudsTAF: Codable {
let type: String
let altitude: Int
}
struct endTimeTAF: Codable {
let repr: String
}
struct WindSpeedTAF: Codable {
let value: Int
}
struct WindGustTAF: Codable {
let value: Int
}
struct WindDirectionTAF: Codable {
let repr: String
}
struct VisibilityTAF: Codable {
let repr: String
}
struct WxcodesTAF: Codable {
let value: String
}
struct StartTimeTAF: Codable {
let repr: String
}
struct EndTimeTAF: Codable {
let repr: String
}
}
struct TimeTAF: Codable {
let repr: String
}
我的解析文件是:
//
// TAFManager.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/24/20.
//
import Foundation
protocol TAFManagerDelegate : class {
func didUpdateTAF(_ weatherManager: TAFManager, weatherTAF: TAFModel)
func didFailWithErrorTAF(error: Error)
}
struct TAFManager {
let TAFURL = "https://avwx.rest/api/taf/"
weak var delegate : TAFManagerDelegate?
func fetchWeatherTAF (stationICAO: String) {
let TAFurlString = "\(TAFURL)\(stationICAO)?token=OVi45FiTDo1LmyodShfOfoizNe5m9wyuO6Mkc95AN-c"
performRequestTAF(with: TAFurlString)
}
func performRequestTAF (with TAFurlString: String) {
if let TAFurl = URL(string: TAFurlString) {
let session = URLSession(configuration: .default)
let taskTAF = session.dataTask(with: TAFurl) { (data, response, error) in
if error != nil {
self.delegate?.didFailWithErrorTAF(error: error!)
return
}
if let safeDataTAF = data {
if let weatherTAF = self.parseJSONTAF(safeDataTAF) {
self.delegate?.didUpdateTAF(self, weatherTAF: weatherTAF)
}
}
}
taskTAF.resume()
print(TAFurlString)
}
}
func parseJSONTAF(_ TAFData: Data) -> TAFModel? {
do {
let decoderTAF = JSONDecoder()
let decodedDataTAF = try decoderTAF.decode(TAFDatas.self, from: TAFData)
let cloudsTAF = decodedDataTAF.clouds
let wxcodesTAF = decodedDataTAF.wx_codes
let forecastTAF = decodedDataTAF.forecast
let lowCloudsTypeTAF = (cloudsTAF.count > 0 ? cloudsTAF[0]?.type : nil) ?? "N/A"
let midCloudsTypeTAF = (cloudsTAF.count > 1 ? cloudsTAF[1]?.type : nil) ?? "N/A"
let highCloudsTypeTAF = (cloudsTAF.count > 2 ? cloudsTAF[2]?.type : nil) ?? "N/A"
let lowCloudsAltTAF = (cloudsTAF.count > 0 ? cloudsTAF[0]?.altitude : nil) ?? 0
let midCloudsAltTAF = (cloudsTAF.count > 1 ? cloudsTAF[1]?.altitude : nil) ?? 0
let highCloudsAltTAF = (cloudsTAF.count > 2 ? cloudsTAF[2]?.altitude : nil) ?? 0
let reportingStationVarTAF = decodedDataTAF.station ?? "N/A"
let windGustValueTAF = decodedDataTAF.wind_gust?.value ?? 0
let windSpeedValueTAF = decodedDataTAF.wind_speed?.value ?? 0
let windDirectionValueTAF = decodedDataTAF.wind_direction?.repr ?? "N/A"
let visibilityValueTAF = decodedDataTAF.visibility?.repr ?? "N/A"
let flightRulesValueTAF = decodedDataTAF.flight_rules ?? "N/A"
let timeReportedTAF = decodedDataTAF.time?.repr ?? "N/A"
let firstWxCode1TAF = (wxcodesTAF.count > 0 ? wxcodesTAF[0]?.value : "N/A") ?? "N/A"
let startTimeTaf = decodedDataTAF.start_time?.repr ?? "N/A"
let endTimeTaf = (forecastTAF.count > 0 ? forecastTAF[0]? : nil) ?? "N/A"
let rawTAFData = (forecastTAF.count > 0 ? forecastTAF[0]?.raw : nil) ?? "N/A"
let weatherTAF = TAFModel(lowestCloudsTypeTAF: lowCloudsTypeTAF , lowestCloudsAltTAF: lowCloudsAltTAF, middleCloudsTypeTAF: midCloudsTypeTAF , middleCloudsAltTAF: midCloudsAltTAF, highestCloudsTypeTAF: highCloudsTypeTAF , highestCloudsAltTAF: highCloudsAltTAF, reportingStationTAF: reportingStationVarTAF, windGustTAF: windGustValueTAF, windSpeedTAF: windSpeedValueTAF, windDirectionTAF: windDirectionValueTAF, visibilityTAF: visibilityValueTAF, flightRulesTAF: flightRulesValueTAF, timeTAF: timeReportedTAF, startTimeTAF: startTimeTaf, endTimeTAF: endTimeTaf, firstWxCodeTAF: firstWxCode1TAF, rawTAF: rawTAFData)
delegate?.didUpdateTAF(self, weatherTAF: weatherTAF)
return weatherTAF
} catch {
delegate?.didFailWithErrorTAF(error: error)
return nil
}
}
}
我的模型文件是:
//
// WeatherModel.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/22/20.
//
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: String
let visibility: String
let flightRules: String
let time: String
let remarks: String
let altimeter: Double
let temperature: String
let dewpoint: String
let firstWxCode: String
var altToString1: String {
return String(format: "%u" + "00 ft", lowestCloudsAlt)
}
var altToString2: String {
return String(format: "%u" + "00 ft", middleCloudsAlt)
}
var altToString3: String {
return String(format: "%u" + "00 ft", highestCloudsAlt)
}
var windGustString: String {
return String(format: "%u" + "kt", windGust)
}
var windSpeedString: String {
return String(format: "%u" + "kt", windSpeed)
}
var altimeterString: String {
return String(format: "%.2f" + " inHg", altimeter as CVarArg)
}
var visUnits: String {
return visibility + " SM"
}
var degUnits: String {
return windDirection + "°"
}
var tempUnits: String {
return temperature + "°C"
}
var dewUnits: String {
return dewpoint + "°C"
}
var flightConditions: String {
switch flightRules {
case "VFR":
return "green"
case "MVFR":
return "blue"
case "IFR":
return "red"
case "LIFR":
return "purple"
default:
return "gray"
}
}
}
我认为主要的障碍是获取那些数据密钥。一旦我到了那里,希望其余的一切都会到位。非常感谢您的提前帮助,祝您今天愉快!
有评论,我的新人JSON
// MARK: - TAFData
struct TAFData: Codable {
let meta: MetaTAF?
let raw, station: String?
let time: TimeTAF?
let remarks: String?
let forecast: [ForecastTAF?]
let startTime, endTime: TimeTAF?
let maxTemp, minTemp: String?
let alts, temps: JSONNull?
enum CodingKeys: String, CodingKey {
case meta, raw, station, time, remarks, forecast
case startTime = "start_time"
case endTime = "end_time"
case maxTemp = "max_temp"
case minTemp = "min_temp"
case alts, temps, units
}
}
// MARK: - Time
struct TimeTAF: Codable {
let repr, dt: String
}
// MARK: - Forecast
struct ForecastTAF: Codable {
let altimeter: String
let clouds: [CloudTAF]
let flightRules: String
let other: [JSONAny]
let sanitized: String
let visibility, windDirection: VisibilityTAF
let windGust: VisibilityTAF?
let windSpeed: VisibilityTAF
let wxCodes: [WxCodeTAF]
let endTime: TimeTAF
let icing: [JSONAny]
let probability: JSONNull?
let raw: String
let startTime: TimeTAF
let turbulence: [JSONAny]
let type: String
let windShear: JSONNull?
let summary: String
enum CodingKeys: String, CodingKey {
case altimeter, clouds
case flightRules = "flight_rules"
case other, sanitized, visibility
case windDirection = "wind_direction"
case windGust = "wind_gust"
case windSpeed = "wind_speed"
case wxCodes = "wx_codes"
case endTime = "end_time"
case icing, probability, raw
case startTime = "start_time"
case turbulence, type
case windShear = "wind_shear"
case summary
}
}
// MARK: - Cloud
struct CloudTAF: Codable {
let repr, type: String
let altitude: Int
let modifier, direction: JSONNull?
}
// MARK: - Visibility
struct VisibilityTAF: Codable {
let repr: String
let value: Int?
let spoken: String
}
// MARK: - WxCode
struct WxCodeTAF: Codable {
let repr, value: String
}
// MARK: - Meta
struct MetaTAF: Codable {
let timestamp: String
}
// MARK: - Units
struct UnitsTAF: Codable {
let altimeter, altitude, temperature, visibility: String
let windSpeed: String
enum CodingKeys: String, CodingKey {
case altimeter, altitude, temperature, visibility
case windSpeed = "wind_speed"
}
}
// MARK: - Encode/decode helpers
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
public func hash(into hasher: inout Hasher) {
// No-op
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
class JSONCodingKey: CodingKey {
let key: String
required init?(intValue: Int) {
return nil
}
required init?(stringValue: String) {
key = stringValue
}
var intValue: Int? {
return nil
}
var stringValue: String {
return key
}
}
class JSONAny: Codable {
let value: Any
static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError {
let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny")
return DecodingError.typeMismatch(JSONAny.self, context)
}
static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError {
let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny")
return EncodingError.invalidValue(value, context)
}
static func decode(from container: SingleValueDecodingContainer) throws -> Any {
if let value = try? container.decode(Bool.self) {
return value
}
if let value = try? container.decode(Int64.self) {
return value
}
if let value = try? container.decode(Double.self) {
return value
}
if let value = try? container.decode(String.self) {
return value
}
if container.decodeNil() {
return JSONNull()
}
throw decodingError(forCodingPath: container.codingPath)
}
static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any {
if let value = try? container.decode(Bool.self) {
return value
}
if let value = try? container.decode(Int64.self) {
return value
}
if let value = try? container.decode(Double.self) {
return value
}
if let value = try? container.decode(String.self) {
return value
}
if let value = try? container.decodeNil() {
if value {
return JSONNull()
}
}
if var container = try? container.nestedUnkeyedContainer() {
return try decodeArray(from: &container)
}
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self) {
return try decodeDictionary(from: &container)
}
throw decodingError(forCodingPath: container.codingPath)
}
static func decode(from container: inout KeyedDecodingContainer<JSONCodingKey>, forKey key: JSONCodingKey) throws -> Any {
if let value = try? container.decode(Bool.self, forKey: key) {
return value
}
if let value = try? container.decode(Int64.self, forKey: key) {
return value
}
if let value = try? container.decode(Double.self, forKey: key) {
return value
}
if let value = try? container.decode(String.self, forKey: key) {
return value
}
if let value = try? container.decodeNil(forKey: key) {
if value {
return JSONNull()
}
}
if var container = try? container.nestedUnkeyedContainer(forKey: key) {
return try decodeArray(from: &container)
}
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) {
return try decodeDictionary(from: &container)
}
throw decodingError(forCodingPath: container.codingPath)
}
static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] {
var arr: [Any] = []
while !container.isAtEnd {
let value = try decode(from: &container)
arr.append(value)
}
return arr
}
static func decodeDictionary(from container: inout KeyedDecodingContainer<JSONCodingKey>) throws -> [String: Any] {
var dict = [String: Any]()
for key in container.allKeys {
let value = try decode(from: &container, forKey: key)
dict[key.stringValue] = value
}
return dict
}
static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws {
for value in array {
if let value = value as? Bool {
try container.encode(value)
} else if let value = value as? Int64 {
try container.encode(value)
} else if let value = value as? Double {
try container.encode(value)
} else if let value = value as? String {
try container.encode(value)
} else if value is JSONNull {
try container.encodeNil()
} else if let value = value as? [Any] {
var container = container.nestedUnkeyedContainer()
try encode(to: &container, array: value)
} else if let value = value as? [String: Any] {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self)
try encode(to: &container, dictionary: value)
} else {
throw encodingError(forValue: value, codingPath: container.codingPath)
}
}
}
static func encode(to container: inout KeyedEncodingContainer<JSONCodingKey>, dictionary: [String: Any]) throws {
for (key, value) in dictionary {
let key = JSONCodingKey(stringValue: key)!
if let value = value as? Bool {
try container.encode(value, forKey: key)
} else if let value = value as? Int64 {
try container.encode(value, forKey: key)
} else if let value = value as? Double {
try container.encode(value, forKey: key)
} else if let value = value as? String {
try container.encode(value, forKey: key)
} else if value is JSONNull {
try container.encodeNil(forKey: key)
} else if let value = value as? [Any] {
var container = container.nestedUnkeyedContainer(forKey: key)
try encode(to: &container, array: value)
} else if let value = value as? [String: Any] {
var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key)
try encode(to: &container, dictionary: value)
} else {
throw encodingError(forValue: value, codingPath: container.codingPath)
}
}
}
static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws {
if let value = value as? Bool {
try container.encode(value)
} else if let value = value as? Int64 {
try container.encode(value)
} else if let value = value as? Double {
try container.encode(value)
} else if let value = value as? String {
try container.encode(value)
} else if value is JSONNull {
try container.encodeNil()
} else {
throw encodingError(forValue: value, codingPath: container.codingPath)
}
}
public required init(from decoder: Decoder) throws {
if var arrayContainer = try? decoder.unkeyedContainer() {
self.value = try JSONAny.decodeArray(from: &arrayContainer)
} else if var container = try? decoder.container(keyedBy: JSONCodingKey.self) {
self.value = try JSONAny.decodeDictionary(from: &container)
} else {
let container = try decoder.singleValueContainer()
self.value = try JSONAny.decode(from: container)
}
}
public func encode(to encoder: Encoder) throws {
if let arr = self.value as? [Any] {
var container = encoder.unkeyedContainer()
try JSONAny.encode(to: &container, array: arr)
} else if let dict = self.value as? [String: Any] {
var container = encoder.container(keyedBy: JSONCodingKey.self)
try JSONAny.encode(to: &container, dictionary: dict)
} else {
var container = encoder.singleValueContainer()
try JSONAny.encode(to: &container, value: self.value)
}
}
}
我可能会使用不同的模型,因为您当前的模型不支持与 JSON:
相同的格式
struct Forecast: Codable {
let altimeter: String
let clouds: [Cloud]
let flightRules: String
let other: [JSONAny]
let sanitized: String
let visibility, windDirection: Visibility
enum CodingKeys: String, CodingKey {
case altimeter, clouds
case flightRules = "flight_rules"
case other, sanitized, visibility
case windDirection = "wind_direction"
}
}
// MARK: - Cloud
struct Cloud: Codable {
let repr, type: String
let altitude: Int
}
// MARK: - Visibility
struct Visibility: Codable {
let repr: String
let value: Int?
let spoken: String
}
这样你就可以使用:
if let cloud = forecast.clouds.first() {
let repr = cloud.repr
.. Your logic
}
我的模型中可能缺少一些东西,但你应该有一个想法