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

Codable模型转字典异常:JSONSerialization生成非字符串键数组求助

解决Codable模型转字典时键格式异常的问题

看起来你遇到的是Codable转字典后,输出的键不带引号(比如accx = "-0.00247...")的问题——其实这只是NSDictionary的调试打印格式,本质上键是NSString类型,但我们可以通过更规范的转换方法得到纯Swift的[String: Any]字典,也就是你想要的标准格式(键带引号的结构)。

下面是具体的解决方案:

1. 给Codable写一个通用的转字典扩展

直接通过JSONEncoder和JSONSerialization结合,一步得到Swift原生字典:

extension Encodable {
    func asSwiftDictionary() throws -> [String: Any] {
        // 先把模型编码成Data
        let encodedData = try JSONEncoder().encode(self)
        // 把Data转成Any,再强转成Swift字典
        guard let dictionary = try JSONSerialization.jsonObject(with: encodedData, options: []) as? [String: Any] else {
            throw NSError(domain: "ModelConversionError", code: 1, userInfo: [NSLocalizedDescriptionKey: "无法将模型转换为Swift字典"])
        }
        return dictionary
    }
}

2. 如何使用这个扩展

假设你的模型结构是这样的:

// 传感器数据模型
struct SensorReading: Codable {
    let accx: String
    let accy: String
    let accz: String
    let gyrox: String
    let gyroy: String
    let gyroz: String
}

// 包含传感器数组的父模型
struct DeviceData: Codable {
    let sensors: [SensorReading]
    // 其他属性...
}

转换代码示例:

// 初始化你的模型
let sampleSensor = SensorReading(accx: "-0.002471923828125", accy: "0.011444091796875", accz: "-1.013595581054688", gyrox: "-0.029818882093399213", gyroy: "0.028939506301455049", gyroz: "0.0044943506556177227")
let deviceModel = DeviceData(sensors: [sampleSensor])

// 执行转换
do {
    let standardDict = try deviceModel.asSwiftDictionary()
    print(standardDict)
    // 输出的sensors数组里的字典会是标准格式:"accx": "-0.00247...", 以此类推
} catch {
    print("转换失败:\(error.localizedDescription)")
}

3. 处理嵌套的Foundation集合(如果需要)

如果你的转换结果里还混有NSArray/NSDictionary(比如直接用JSONSerialization得到的结果),可以用递归方法把它们转成Swift原生集合:

func convertToSwiftCollection(_ value: Any) -> Any {
    if let nsDict = value as? [String: Any] {
        return nsDict.mapValues(convertToSwiftCollection)
    } else if let nsArray = value as? [Any] {
        return nsArray.map(convertToSwiftCollection)
    } else {
        return value
    }
}

// 使用示例:
let foundationDict = try JSONSerialization.jsonObject(with: encodedData) as? [String: Any]
let pureSwiftDict = convertToSwiftCollection(foundationDict!) as? [String: Any]

为什么之前的输出看起来键不是字符串?

你看到的accx = "-0.00247..."是NSDictionary的默认打印格式,它的键实际上是NSString,可以桥接成Swift的String,但Swift原生字典的打印会显示带引号的键,这就是你需要的标准JSON风格格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:41:39