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

Swift使用Decodable解析动态key JSON时key顺序乱序如何解决?

问题根源

你当前代码丢失顺序的核心原因是 Swift 标准库的Dictionary为无序哈希表结构,本身不保留键的插入顺序,和解析逻辑无关。iOS 13+、macOS 10.15+ 版本的JSONDecoder返回的allKeys已经默认保留了源JSON中键的出现顺序,你看到的顺序混乱是存入普通字典后才发生的。

解决方案

方案1:使用官方Swift Collections库的OrderedDictionary(推荐)

OrderedDictionary是苹果官方Swift Collections组件提供的有序字典结构,既保留普通字典的按键快速查询能力,又能严格保留键的插入顺序,用法和普通字典几乎完全一致。

  1. 首先引入Swift Collections依赖
  2. 修改代码如下:
import Collections

struct ChannelSequence : Codable {
    // 将原普通字典替换为有序字典
    public var innerMap: OrderedDictionary<String, InnerChannelNode>  
    
    private struct CustomCodingKeys: CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int?
        init?(intValue: Int) {
            return nil
        }
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CustomCodingKeys.self) 
        self.innerMap = [:]
        // 按allKeys的顺序插入有序字典即可保留原顺序
        for key in values.allKeys {
            let value = try values.decode(InnerChannelNode.self, forKey: key)
            self.innerMap[key.stringValue] = value
        }
    }
}

方案2:无需第三方依赖,自行维护顺序

如果不想引入额外依赖,可以同时存储有序键值对数组和普通字典,分别满足顺序遍历和快速查询的需求:

struct ChannelSequence : Codable {
    // 存储有序键值对,用于顺序遍历
    public var orderedNodes: [(key: String, value: InnerChannelNode)]
    // 存储普通字典,用于按键快速查询
    public var nodeMap: [String: InnerChannelNode]
    
    private struct CustomCodingKeys: CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int?
        init?(intValue: Int) {
            return nil
        }
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CustomCodingKeys.self) 
        self.orderedNodes = []
        self.nodeMap = [:]
        for key in values.allKeys {
            let value = try values.decode(InnerChannelNode.self, forKey: key)
            self.orderedNodes.append((key.stringValue, value))
            self.nodeMap[key.stringValue] = value
        }
    }
}

低版本兼容注意

如果你的应用最低部署版本低于iOS 13或macOS 10.15,JSONDecoder的allKeys不保证保留源顺序,这种场景下需要改用JSONSerialization配合.mutableContainersAndLeaves选项先解析出有序结构再做后续处理。

内容的提问来源于stack exchange,提问作者byJeevan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 19:54:04