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

如何将Swift Codable数据转换为[String: CustomStringConvertible]字典

转换失败的根本原因

两类写法的底层类型完全不同:

  • 直接声明的["a": "a", "b": 1]是Swift原生字典,存储的原生String、Int类型默认遵守CustomStringConvertible协议,所以可以直接转换成功。
  • 从JSONSerialization反序列化得到的字典,所有数值类型会被桥接为OC的NSNumber、字符串桥接为NSString,这两类桥接类型没有显式遵守Swift的CustomStringConvertible协议,因此整字典直接做类型转换会返回nil。
解决方案

方案1:遍历转换JSON序列化结果

对JSONSerialization输出的字典做逐字段转换,兼容现有实现逻辑,改造成本最低:

extension Encodable {
    func toStringConvertibleDict() throws -> [String: CustomStringConvertible] {
        let jsonData = try JSONEncoder().encode(self)
        guard let rawDict = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] else {
            throw NSError(domain: "CodableConvert", code: -1, userInfo: [NSLocalizedDescriptionKey: "序列化结果不是字典结构"])
        }
        var result = [String: CustomStringConvertible]()
        for (key, value) in rawDict {
            switch value {
            case let str as String:
                result[key] = str
            case let num as NSNumber:
                // 可根据需求选择保留原生数值类型或直接取字符串
                // 以下为保留原类型的写法:
                if num.objCType.pointee == 99 { // C语言bool类型编码
                    result[key] = num.boolValue
                } else if num.doubleValue == Double(num.intValue) {
                    result[key] = num.intValue
                } else {
                    result[key] = num.doubleValue
                }
                // 若不需要保留类型直接取字符串:result[key] = num.description
            default:
                // 按需补充嵌套字典、数组等其他类型的转换逻辑
                break
            }
        }
        return result
    }
}

// 调用示例
let model = Model(a: "a", b: 1)
let parameters = try model.toStringConvertibleDict()
// 转换后直接得到[String: CustomStringConvertible]类型

方案2:自定义Encoder直接转换

不需要走JSON编解码流程,性能更高,适合不需要JSON兼容的场景:

struct DescriptionDictEncoder {
    func encode<T: Encodable>(_ value: T) throws -> [String: CustomStringConvertible] {
        let mirror = Mirror(reflecting: value)
        var result = [String: CustomStringConvertible]()
        for case let (key?, value) in mirror.children {
            guard let convertibleValue = value as? CustomStringConvertible else {
                throw NSError(domain: "DescriptionDictEncoder", code: -1, userInfo: [NSLocalizedDescriptionKey: "字段\(key)不满足CustomStringConvertible要求"])
            }
            result[key] = convertibleValue
        }
        return result
    }
}

// 调用示例
let encoder = DescriptionDictEncoder()
let parameters = try encoder.encode(Model(a: "a", b: 1))

如果需要支持嵌套Codable类型,只需要递归调用encode方法处理子节点即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 05:06:03