Swift解析动态结构JSON遇阻,求Alarms数组解析方案
解决动态结构JSON的Codable解析问题
针对你遇到的alarms字段动态结构(包含数字键的告警项和nb_alarms字段)的解析问题,核心是不要把alarms当成数组处理,而是将其视为混合了固定字段和动态键的字典,通过自定义解码逻辑提取有序告警项和告警数量。
步骤1:定义基础数据结构
首先定义告警项和配置项的基础Codable结构(根据你的实际JSON字段调整):
// 配置项结构(你原有的可正常解析的结构) struct ConfigItem: Codable { let name: String // 示例字段,替换为你的实际字段 } // 告警项结构 struct AlarmItem: Codable { let id: Int let message: String // 示例字段,替换为你的实际字段 }
步骤2:自定义Alarms容器结构
创建一个容器结构处理alarms的动态键,实现自定义解码逻辑:
// 自定义动态CodingKey,用于处理字符串类型的动态键 struct DynamicCodingKey: CodingKey { let stringValue: String init?(stringValue: String) { self.stringValue = stringValue } let intValue: Int? = nil init?(intValue: Int) { return nil } } struct AlarmsContainer: Codable { let alarmItems: [AlarmItem] // 有序的告警项列表 let nbAlarms: Int // 告警数量 enum FixedKeys: String, CodingKey { case nbAlarms = "nb_alarms" } init(from decoder: Decoder) throws { // 用动态CodingKey容器解析所有键值对 let dynamicContainer = try decoder.container(keyedBy: DynamicCodingKey.self) // 提取固定字段nb_alarms nbAlarms = try dynamicContainer.decode(Int.self, forKey: DynamicCodingKey(stringValue: FixedKeys.nbAlarms.rawValue)!) // 筛选数字键的告警项,保留键值对以便排序 var keyValuePairs = [(key: String, item: AlarmItem)]() for key in dynamicContainer.allKeys { // 跳过nb_alarms,只处理数字格式的键 guard key.stringValue != FixedKeys.nbAlarms.rawValue, Int(key.stringValue) != nil else { continue } let item = try dynamicContainer.decode(AlarmItem.self, forKey: key) keyValuePairs.append((key.stringValue, item)) } // 按数字键的数值升序排序,得到有序告警列表 keyValuePairs.sort { Int($0.key)! < Int($1.key)! } alarmItems = keyValuePairs.map { $0.item } } }
步骤3:定义最外层响应结构
将config和自定义的AlarmsContainer组合成完整的响应结构:
struct ServerResponse: Codable { let config: [ConfigItem] let alarms: AlarmsContainer }
步骤4:解码示例
使用标准JSONDecoder解析数据:
// 示例JSON数据(替换为你的服务器返回数据) let sampleJson = """ { "config": [{"name": "系统配置1"}, {"name": "系统配置2"}], "alarms": { "0": {"id": 1, "message": "温度阈值超标"}, "2": {"id": 3, "message": "电源波动"}, "1": {"id": 2, "message": "压力异常"}, "nb_alarms": 3 } } """.data(using: .utf8)! do { let response = try JSONDecoder().decode(ServerResponse.self, from: sampleJson) print("告警总数:\(response.alarms.nbAlarms)") print("有序告警列表:") response.alarms.alarmItems.enumerated().forEach { index, item in print("\(index+1). ID:\(item.id),内容:\(item.message)") } } catch { print("解码失败:\(error.localizedDescription)") }
错误原因说明
你之前遇到的Expected to decode String but found a dictionary instead错误,本质是错误地将alarms字段按数组解析,但实际它是一个字典类型。通过自定义动态CodingKey和容器解码,可以正确区分固定字段和动态数字键,同时保证告警项的有序性。
内容的提问来源于stack exchange,提问作者tiamat
相关产品推荐
相关产品推荐

