在Swift中如何解析包含混合类型元素的JSON数组?
解决方案
1 处理417错误
417 Expectation Failed不属于JSON解析错误,是请求发送阶段服务端返回的异常,原因是AFNetworking默认会对请求体超过1KB的请求自动添加Expect: 100-continue请求头,很多后端服务未适配该逻辑就会返回417。
修复方案:在全局AF会话配置中清空Expect请求头即可,示例代码:
let configuration = URLSessionConfiguration.af.default configuration.httpAdditionalHeaders?["Expect"] = "" let session = Session(configuration: configuration) // 后续所有请求都用这个自定义的session发起即可
也可以直接在你的APIRouter的请求头配置中添加Expect: ""字段,效果一致。
2 实现异构JSON结构解析
你的原有结构体和实际返回结构存在三处不匹配:
- 实际返回根层级不是Product对象,而是包含id、users、products数组的外层结构
- Product的type字段你定义为Int类型,但实际返回是字符串类型(如
XDFT、ZRFT) - details数组包含多种结构的对象,不能直接定义为单一的[Detail1]类型
适配后的结构体定义
可以通过带关联值的枚举包装不同类型的详情,手动实现解码逻辑判断类型:
// 根响应结构体 struct ProductResponse: Codable { let id: String let users: [User] let products: [Product] } struct User: Codable { let name: String let surname: String } // 详情类型枚举包装 enum Detail: Codable { case type1(Detail1) case type2(Detail2) case type3(Detail3) case unknown init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() // 尝试依次解码不同类型 if let d1 = try? container.decode(Detail1.self) { self = .type1(d1) return } if let d2 = try? container.decode(Detail2.self) { self = .type2(d2) return } if let d3 = try? container.decode(Detail3.self) { self = .type3(d3) return } self = .unknown } } struct Product: Codable { let id: Int let type: String // 修正为字符串类型匹配返回值 let details: [Detail] // 改为枚举类型 } struct Detail1: Codable { let id: Int let name: String let surname: String } struct Detail2: Codable { let id: Int let title: String let subtitle: String } struct Detail3: Codable { let id: Int let thickness: Int let length: Int }
修改请求方法适配返回结构
将原请求的返回类型从Product改为ProductResponse即可:
static func getProduct(id:Int, completion:@escaping (Result<ProductResponse, AFError>)->Void){ performRequest(route: APIRouter.getProduct(id: id), completion: completion) }
使用示例
拿到Product后,可直接通过switch判断detail的类型做对应展示:
product.details.forEach { detail in switch detail { case .type1(let d1): // 展示Detail1的UI逻辑 print(d1.name, d1.surname) case .type2(let d2): // 展示Detail2的UI逻辑 print(d2.title, d2.subtitle) case .type3(let d3): // 展示Detail3的UI逻辑 print(d3.thickness, d3.length) case .unknown: // 兼容未知类型兜底逻辑 break } }
内容的提问来源于stack exchange,提问作者uzman
相关产品推荐
相关产品推荐

