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
相关产品推荐
相关产品推荐

