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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:30:03