You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 14:42:09