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

