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

Swift解码含嵌套JSON与数组的数据遇阻,求解决方案

解决Swift中解码嵌套JSON数组的问题

首先,我明白你刚接触Swift,在解码这个嵌套结构的JSON时遇到了麻烦——你想把serviceCenter数组转成Decodable对象,但没找对正确的结构映射方式。我们可以用Swift的Codable协议来优雅地解决这个问题,比手动用JSONSerialization解析要简洁得多。

第一步:定义对应JSON结构的Codable结构体

首先我们需要把JSON的层级结构完整映射成Swift结构体:

  1. 顶层是一个数组,包含两个元素:一个validation对象,一个result对象
  2. result内部包含serviceCenter数组,每个元素是具体的服务中心信息

先定义最底层的ServiceCenter结构体,注意JSON里的字段类型(比如bDamage是字符串"1",我们可以自定义解码把它转成Bool):

struct ServiceCenter: Codable {
    let model: String
    let color: String
    let make: String
    let sTag: String
    let sVin: String
    let sMiles: String
    let bDamage: Bool
    let dDateTime: String
    
    // 自定义解码,把"1"/"0"字符串转成Bool
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        model = try container.decode(String.self, forKey: .model)
        color = try container.decode(String.self, forKey: .color)
        make = try container.decode(String.self, forKey: .make)
        sTag = try container.decode(String.self, forKey: .sTag)
        sVin = try container.decode(String.self, forKey: .sVin)
        sMiles = try container.decode(String.self, forKey: .sMiles)
        // 处理bDamage字段
        let damageStr = try container.decode(String.self, forKey: .bDamage)
        bDamage = damageStr == "1"
        dDateTime = try container.decode(String.self, forKey: .dDateTime)
    }
}

然后定义包含serviceCenter数组的Result结构体:

struct Result: Codable {
    let serviceCenter: [ServiceCenter]
}

最后,我们用枚举来处理顶层数组的两种不同元素(validation和result):

enum ResponseElement: Codable {
    case validation(Validation)
    case result(Result)
    
    enum CodingKeys: String, CodingKey {
        case validation, result
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 尝试解码validation
        if let validation = try container.decodeIfPresent(Validation.self, forKey: .validation) {
            self = .validation(validation)
        } 
        // 尝试解码result
        else if let result = try container.decodeIfPresent(Result.self, forKey: .result) {
            self = .result(result)
        } 
        // 都不是的话抛出错误
        else {
            throw DecodingError.dataCorrupted(DecodingError.Context(
                codingPath: container.codingPath,
                debugDescription: "无法识别的响应元素类型"
            ))
        }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case .validation(let val):
            try container.encode(val, forKey: .validation)
        case .result(let res):
            try container.encode(res, forKey: .result)
        }
    }
}

// 定义Validation结构体(虽然你不需要处理,但解码需要用到)
struct Validation: Codable {
    let bValid: Bool
    let sDescription: String
}

第二步:解码JSON并获取serviceCenter数组

现在可以用JSONDecoder来解码整个JSON,然后提取出serviceCenter数组:

do {
    // 解码顶层数组
    let responseElements = try JSONDecoder().decode([ResponseElement].self, from: data)
    
    // 找到数组中的result元素
    if let resultElement = responseElements.first(where: { element in
        if case .result(_) = element { return true }
        return false
    }) {
        // 提取result对象
        if case .result(let result) = resultElement {
            let serviceCenters = result.serviceCenter
            
            // 遍历处理每个serviceCenter
            for sc in serviceCenters {
                print("品牌:\(sc.make),型号:\(sc.model),颜色:\(sc.color)")
                // 其他字段可以按需使用
            }
        }
    }
} catch {
    print("解码失败:\(error.localizedDescription)")
    print(error) // 打印详细错误信息,方便调试
}

如果你想简化(适合刚入门理解)

如果你觉得枚举有点复杂,也可以结合JSONSerialization和Codable来逐层解析:

do {
    // 先解码顶层数组
    let topLevelArray = try JSONSerialization.jsonObject(with: data) as! [[String: Any]]
    // 取第二个元素(index为1)里的result字典
    guard let resultDict = topLevelArray[1]["result"] as? [String: Any] else {
        print("找不到result字段")
        return
    }
    // 把result字典转成Data,再解码成Result结构体
    let resultData = try JSONSerialization.data(withJSONObject: resultDict)
    let result = try JSONDecoder().decode(Result.self, from: resultData)
    
    // 现在就可以使用serviceCenter数组了
    for sc in result.serviceCenter {
        print(sc)
    }
} catch {
    print("处理失败:\(error)")
}

为什么你之前的Decodable尝试失败?

大概率是因为你没有正确映射整个JSON的层级——serviceCenter不是直接在顶层,而是嵌套在result里,而result又在顶层数组的第二个元素中。直接解码serviceCenter数组的话,解码器找不到对应的层级,所以会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:09:51