解码字典中的字典-JSON / Swift

如何解决解码字典中的字典-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,但无法弄清楚如何从预测内部提取数据:clouds:repr(或类似的其他嵌套内容)。我可以成功提取数据,例如:预测:原始。我尝试了没有嵌套在第一个结构中的结构,但是它没有用(按预期,数据是内部的另一个索引)。

我的解码文件是:

//
//  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,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,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 
}

我的模型中可能缺少一些东西,但是您应该有个主意

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res