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

Swift中如何解码包含多种类型元素的JSON数组?

解决方案

你的解码失败核心原因是:Job枚举定义的CodingKeys(journeyDetail、booking)在JSON里根本不存在——JSON数组里的元素是直接携带对应字段的,第一个元素有journey和bookings,后面的元素有id和address,所以不能用自定义键的容器去匹配,得通过检查元素是否包含特定字段来区分类型。

以下是修正后的完整代码:

1. 修正数据结构与解码逻辑

import Foundation

// 匹配JSON根节点结构:直接包含archives数组
struct Response: Decodable {
    let archives: [Job]
}

struct Booking: Decodable {
    let id: Int
    let address: String
}

struct JourneyDetail: Decodable {
    let journey: Journey
    let bookings: [Booking]
}

struct Journey: Decodable {
    let id: Int
    let name: String
}

// 重写Job枚举的解码逻辑
enum Job: Decodable {
    case journeyDetail(JourneyDetail)
    case booking(Booking)

    init(from decoder: Decoder) throws {
        // 获取当前元素的键值容器,用动态CodingKey支持任意键检查
        let container = try decoder.container(keyedBy: DynamicCodingKey.self)
        
        // 检查是否包含"journey"键,包含则解码为JourneyDetail
        if container.contains(DynamicCodingKey(stringValue: "journey")!) {
            let detail = try JourneyDetail(from: decoder)
            self = .journeyDetail(detail)
            return
        }
        
        // 否则解码为Booking
        let booking = try Booking(from: decoder)
        self = .booking(booking)
    }
    
    // 动态CodingKey,用于检查任意字符串键是否存在
    private struct DynamicCodingKey: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int?
        init?(intValue: Int) { return nil }
    }
}

2. 测试解码代码

// 你的JSON示例
let jsonString = """
{"archives": [
      {
        "journey": {
          "id": 5,
          "name": "test name"
        },
        "bookings": [
          {
            "id": 563219,
            "address": "test address"         
          },
          {
            "id": 563220,
            "address": "test address 2"   
          }
        ]
      },
      {
          "id": 563221,
          "address": "test address 3"  
      },
      {
          "id": 563222,
          "address": "test address 4"  
      }
    ]
  }
"""

if let jsonData = jsonString.data(using: .utf8) {
    do {
        let response = try JSONDecoder().decode(Response.self, from: jsonData)
        // 遍历解码结果
        for job in response.archives {
            switch job {
            case .journeyDetail(let detail):
                print("=== 行程详情 ===")
                print("行程ID: \(detail.journey.id),名称: \(detail.journey.name)")
                print("关联订单数: \(detail.bookings.count)")
            case .booking(let booking):
                print("=== 单个订单 ===")
                print("订单ID: \(booking.id),地址: \(booking.address)")
            }
        }
    } catch {
        print("解码失败:\(error)")
    }
}

关键说明

  • 去掉了原代码中多余的Archive结构,直接让Response匹配JSON根节点的archives字段
  • 用DynamicCodingKey实现动态键检查,通过判断元素是否包含journey字段来区分两种类型
  • 解码时直接复用JourneyDetail和Booking的默认解码逻辑,无需额外自定义键映射

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:18:04