Swift使用Decodable解析动态key JSON时key顺序乱序如何解决?
问题根源
你当前代码丢失顺序的核心原因是 Swift 标准库的Dictionary为无序哈希表结构,本身不保留键的插入顺序,和解析逻辑无关。iOS 13+、macOS 10.15+ 版本的JSONDecoder返回的allKeys已经默认保留了源JSON中键的出现顺序,你看到的顺序混乱是存入普通字典后才发生的。
解决方案
方案1:使用官方Swift Collections库的OrderedDictionary(推荐)
OrderedDictionary是苹果官方Swift Collections组件提供的有序字典结构,既保留普通字典的按键快速查询能力,又能严格保留键的插入顺序,用法和普通字典几乎完全一致。
- 首先引入Swift Collections依赖
- 修改代码如下:
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
相关产品推荐
相关产品推荐

