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

如何使用Swift 4 Codable解析键为Int数组式的JSON数据?

解决方案:Swift 4 Codable解析键为字符串数字的JSON

这个问题很常见——当JSON的键是字符串形式的数字时,直接用[Int: YourModel]解码会失败,因为JSON的键本质上都是字符串类型。下面给你几种可行的方案,从快速实现到优雅复用:

方案1:直接解码为[String: Document](最简单)

先定义基础的Document模型,它能直接映射JSON里的单个文档结构:

struct Document: Codable {
    let name: String
    let cmisid: String
}

然后直接用字典类型解码,之后按需转换键的类型:

// 假设jsonData是你的JSON数据(从文件/网络获取的Data实例)
do {
    let stringKeyedDict = try JSONDecoder().decode([String: Document].self, from: jsonData)
    
    // 转成Int键的字典
    let intKeyedDict = stringKeyedDict.reduce(into: [Int: Document]()) { result, entry in
        if let intKey = Int(entry.key) {
            result[intKey] = entry.value
        }
    }
    
    // 或者直接转成按数字顺序排列的文档数组
    let sortedDocuments = intKeyedDict.sorted { $0.key < $1.key }.map { $0.value }
} catch {
    print("解码出错:\(error.localizedDescription)")
}

这种方式不需要自定义CodingKey,适合快速实现,但如果需要多次处理这类JSON,自定义模型会更整洁。

方案2:自定义模型+动态CodingKey(优雅复用)

如果希望直接解码成[Int: Document]或整理好的数组,可以自定义一个容器模型,配合动态CodingKey来处理字符串形式的数字键:

步骤1:定义动态CodingKey

这个CodingKey可以适配任意字符串/数字键,是处理动态键的核心:

struct DynamicCodingKey: CodingKey {
    let stringValue: String
    let intValue: Int?
    
    init?(stringValue: String) {
        self.stringValue = stringValue
        self.intValue = Int(stringValue)
    }
    
    init?(intValue: Int) {
        self.stringValue = "\(intValue)"
        self.intValue = intValue
    }
}

步骤2:定义容器模型

struct DocumentCollection: Codable {
    let documents: [Int: Document]
    // 可选:添加计算属性,直接得到按数字顺序排列的文档数组
    var sortedDocuments: [Document] {
        documents.sorted { $0.key < $1.key }.map { $0.value }
    }
    
    // 自定义解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicCodingKey.self)
        var tempDict = [Int: Document]()
        
        // 遍历所有键,转成Int后解码对应的值
        for key in container.allKeys {
            guard let intKey = Int(key.stringValue) else {
                throw DecodingError.dataCorrupted(
                    DecodingError.Context(
                        codingPath: [key],
                        debugDescription: "键\(key.stringValue)不是有效的整数"
                    )
                )
            }
            let document = try container.decode(Document.self, forKey: key)
            tempDict[intKey] = document
        }
        
        documents = tempDict
    }
    
    // 如果需要把模型转回JSON,实现编码逻辑(可选)
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: DynamicCodingKey.self)
        for (intKey, document) in documents {
            guard let codingKey = DynamicCodingKey(stringValue: "\(intKey)") else {
                throw EncodingError.invalidValue(
                    intKey,
                    EncodingError.Context(
                        codingPath: [],
                        debugDescription: "无法将整数\(intKey)转换为编码键"
                    )
                )
            }
            try container.encode(document, forKey: codingKey)
        }
    }
}

步骤3:使用模型解码

do {
    let collection = try JSONDecoder().decode(DocumentCollection.self, from: jsonData)
    // 直接获取Int键的字典
    print(collection.documents[0]?.name) // 输出"legaldoc.pdf"
    // 或者直接获取排序后的数组
    let sortedDocs = collection.sortedDocuments
    sortedDocs.forEach { print($0.name) }
} catch {
    print("解码失败:\(error)")
}

关键说明

  • JSON的键本质上都是字符串,所以Swift默认的JSONDecoder无法直接把字符串键映射到Int类型的字典键,必须手动转换
  • 动态DynamicCodingKey是核心,它允许我们处理任意字符串形式的键,再在解码时转成需要的Int类型
  • 如果不需要编码功能,可以省略encode(to:)方法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:30:10