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

Swift 4.1如何解析未知结构JSON?Codable是否适用?

完全可以用Codable搞定这种结构不确定的JSON!别被未知结构吓到,Swift 4.1的Codable其实灵活得很,给你分享两个实用的解决方案:

方案1:自定义Codable枚举处理多类型字段

这是最优雅也最符合Codable设计思想的方式——我们可以定义一个枚举,把foo可能出现的所有类型(字符串、整数、嵌套对象)都囊括进去,让它遵循Codable协议:

enum FlexibleValue: Codable {
    case string(String)
    case int(Int)
    case object([String: FlexibleValue])
    
    // 解码逻辑:尝试按顺序匹配类型
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let stringVal = try? container.decode(String.self) {
            self = .string(stringVal)
        } else if let intVal = try? container.decode(Int.self) {
            self = .int(intVal)
        } else if let objVal = try? container.decode([String: FlexibleValue].self) {
            self = .object(objVal)
        } else {
            throw DecodingError.dataCorruptedError(
                in: container, 
                debugDescription: "不支持的字段类型"
            )
        }
    }
    
    // 编码逻辑:根据枚举case对应编码
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let val): try container.encode(val)
        case .int(let val): try container.encode(val)
        case .object(let val): try container.encode(val)
        }
    }
}

接下来定义主模型,把foo的类型设为我们刚写的FlexibleValue:

struct DynamicResponse: Codable {
    let foo: FlexibleValue
}

现在不管foo是字符串、数字还是嵌套对象,都能轻松解析,之后用switch就能对应处理不同类型:

// 示例JSON:这里可以替换成你提到的任意一种结构
let jsonStr = """
{"foo": {"baz": "bar"}}
"""
guard let jsonData = jsonStr.data(using: .utf8) else { return }

do {
    let response = try JSONDecoder().decode(DynamicResponse.self, from: jsonData)
    switch response.foo {
    case .string(let str):
        print("foo是字符串:\(str)")
    case .int(let num):
        print("foo是整数:\(num)")
    case .object(let obj):
        print("foo是嵌套对象:\(obj)")
        // 要是想访问嵌套的baz字段,继续用switch就行
        if let bazVal = obj["baz"] {
            switch bazVal {
            case .string(let bazStr):
                print("嵌套的baz值是:\(bazStr)")
            default: break
            }
        }
    }
} catch {
    print("解码出错:\(error.localizedDescription)")
}

方案2:结合JSONSerialization做兜底(简单但不够优雅)

如果你觉得写枚举太麻烦,也可以先用JSONSerialization把JSON转成[String: Any],再手动判断类型——不过这种方式会失去Codable的类型安全优势,容易出现类型转换错误,适合快速临时处理:

let jsonStr = """
{"foo": 1}
"""
guard let jsonData = jsonStr.data(using: .utf8) else { return }

do {
    if let jsonObj = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] {
        switch jsonObj["foo"] {
        case let str as String:
            print("foo是字符串:\(str)")
        case let num as Int:
            print("foo是整数:\(num)")
        case let obj as [String: Any]:
            print("foo是嵌套对象:\(obj)")
        default:
            print("foo的类型不支持")
        }
    }
} catch {
    print("解析出错:\(error.localizedDescription)")
}

补充:处理完全未知的JSON结构

如果不止是foo,整个JSON的结构都不确定,你可以直接把整个JSON解析成[String: FlexibleValue],用法和上面的枚举方案一致,同样能灵活处理任意层级的未知结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:28:58