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

Swift JSON解码动态字符串键时排序丢失问题求助

解决Swift解码动态键JSON时丢失顺序的问题

我明白你遇到的困扰了——Swift标准库的Dictionary是无序集合,解码带动态键的JSON对象时,原始的键顺序会直接丢失。结合你的场景(已经有URL传入的指定顺序列表,或者需要保留JSON本身的顺序),给你几个实用的解决方案:

方法1:利用URL传入的顺序列表(最简单可靠)

既然你已经通过URL拿到了明确的键顺序列表,完全可以先解码成普通字典,再根据这个列表重新构建有序的Devise数组。这种方法不需要依赖JSON的顺序,只要URL传入的列表正确就没问题。

示例代码:

// 假设你从URL参数中拿到的顺序列表
let urlKeyOrder: [String] = ["dynamickey1", "dynamickey2", ...]

struct Devise: Codable {
    let nom: String
    let EUR: Float
    let ETH: Float
    
    // 映射JSON里的字段到结构体属性(根据你的实际JSON调整)
    enum CodingKeys: String, CodingKey {
        case infos1 = "EUR"
        case infos2 = "ETH"
    }
    
    // 自定义初始化,方便后续设置nom
    init(nom: String, eur: Float, eth: Float) {
        self.nom = nom
        self.EUR = eur
        self.ETH = eth
    }
    
    // 遵循Codable的默认解码(只处理EUR和ETH)
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.EUR = try container.decode(Float.self, forKey: .infos1)
        self.ETH = try container.decode(Float.self, forKey: .infos2)
        self.nom = "" // 后续通过顺序列表设置
    }
}

// 解码逻辑
let jsonData: Data = // 你的JSON数据
let decoder = JSONDecoder()
let deviseDict = try decoder.decode([String: Devise].self, from: jsonData)

// 根据URL传入的顺序构建有序数组
let orderedDevises = urlKeyOrder.compactMap { key in
    guard var devise = deviseDict[key] else {
        // 处理键不存在的情况,比如返回nil跳过
        return nil
    }
    devise.nom = key
    return devise
}

方法2:用Swift Collections的OrderedDictionary保留JSON原始顺序

如果你需要严格保留JSON本身的键顺序,可以使用苹果官方的Swift Collections库,它提供了OrderedDictionary——一种会保留键插入顺序的字典类型。

步骤:

  1. 通过Swift Package Manager添加依赖:在你的Package.swift中加入:
dependencies: [
    .package(url: "https://github.com/apple/swift-collections.git", from: "1.0.0")
],
targets: [
    .target(
        name: "YourTargetName",
        dependencies: [.product(name: "Collections", package: "swift-collections")]
    )
]
  1. 解码并转换为有序数组:
import Collections

struct Devise: Codable {
    let nom: String
    let EUR: Float
    let ETH: Float
    
    enum CodingKeys: String, CodingKey {
        case infos1 = "EUR"
        case infos2 = "ETH"
    }
    
    init(nom: String, eur: Float, eth: Float) {
        self.nom = nom
        self.EUR = eur
        self.ETH = eth
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.EUR = try container.decode(Float.self, forKey: .infos1)
        self.ETH = try container.decode(Float.self, forKey: .infos2)
        self.nom = ""
    }
}

// 解码为OrderedDictionary
let decoder = JSONDecoder()
let orderedDict = try decoder.decode(OrderedDictionary<String, Devise>.self, from: jsonData)

// 转换为带nom的有序数组
let orderedDevises = orderedDict.map { key, var devise in
    devise.nom = key
    return devise
}

方法3:自定义解码逻辑(无需外部库)

如果不想引入外部库,可以手动实现解码逻辑,遍历JSON的键值对并保留顺序:

struct DataPrix: Codable {
    let devises: [Devise]
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicCodingKey.self)
        var devisesArray = [Devise]()
        
        // 遍历所有键,这里的顺序就是JSON的原始顺序
        for key in container.allKeys {
            let nestedContainer = try container.nestedContainer(keyedBy: Devise.CodingKeys.self, forKey: key)
            let eur = try nestedContainer.decode(Float.self, forKey: .infos1)
            let eth = try nestedContainer.decode(Float.self, forKey: .infos2)
            devisesArray.append(Devise(nom: key.stringValue, eur: eur, eth: eth))
        }
        
        self.devises = devisesArray
    }
    
    // 自定义动态CodingKey,用于匹配JSON的动态键
    private struct DynamicCodingKey: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        
        let intValue: Int? = nil
        init?(intValue: Int) { return nil }
    }
}

struct Devise {
    let nom: String
    let EUR: Float
    let ETH: Float
    
    enum CodingKeys: String, CodingKey {
        case infos1, infos2
    }
}

// 使用方式
let decoder = JSONDecoder()
let dataPrix = try decoder.decode(DataPrix.self, from: jsonData)
// dataPrix.devises就是按JSON原始顺序排列的数组

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:42:19