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

如何为Destination实现带手动解码的Enum类型?

问题描述

给定如下JSON响应:

{
  "Details": {
    "Attachments": [],
    "place": {
      "destination": {
        "type": "international",
        "Id": "superman",
        "locationType": "City",
        "Name": "Kent"
      },
      "package": 52.32,
      "description": "Dinner"
    }
  }
}

该响应中,destination节点仅type为必填项,其余参数均为可选,且返回的参数会随type的不同而变化(例如type为international时返回country、id、currency等)。

目前使用如下Decodable结构体处理:

public struct Destination: Decodable, Equatable {
    public let Id: String?
    public let Name: String?
    public let city: String?
    public let locationType: String?
    public let pinCode: String?
    public let country: String?
    public let state: String?
    public let currency: String?
    public let language: String?
    public let type: Type
}

希望将其改为带关联值的枚举形式,示例如下:

enum Destination {
case international(country: String, id: String, currency: String)
case national(state: String, language: String, pincode: String)
}

请问该如何着手实现这种方式的手动解码?


实现步骤

要实现带关联值的枚举手动解码,需让枚举遵循Decodable协议,并手动实现init(from decoder: Decoder)方法,具体步骤如下:

1. 完善枚举定义

首先定义对应type字段的枚举,再完善带关联值的Destination枚举(关联值设为可选类型,适配JSON中字段可选的特性):

// 对应type字段的可选值
enum DestinationType: String, Decodable {
    case international
    case national
}

// 带关联值的目标枚举,遵循Decodable和Equatable
enum Destination: Decodable, Equatable {
    case international(id: String?, name: String?, locationType: String?, country: String?, currency: String?)
    case national(id: String?, name: String?, locationType: String?, state: String?, language: String?, pinCode: String?)
}

2. 手动实现解码逻辑

在Destination枚举内部添加CodingKeys和init(from decoder: Decoder)方法,按type分支解析对应关联值:

enum Destination: Decodable, Equatable {
    // ... 省略已定义的case
    
    // 定义所有可能用到的JSON字段Key
    enum CodingKeys: String, CodingKey {
        case type, Id, Name, locationType, country, currency, state, language, pinCode
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 先解析必填的type字段,确定枚举分支
        let type = try container.decode(DestinationType.self, forKey: .type)

        switch type {
        case .international:
            // 解析国际类型对应的可选字段
            let id = try container.decodeIfPresent(String.self, forKey: .Id)
            let name = try container.decodeIfPresent(String.self, forKey: .Name)
            let locationType = try container.decodeIfPresent(String.self, forKey: .locationType)
            let country = try container.decodeIfPresent(String.self, forKey: .country)
            let currency = try container.decodeIfPresent(String.self, forKey: .currency)
            self = .international(id: id, name: name, locationType: locationType, country: country, currency: currency)
            
        case .national:
            // 解析国内类型对应的可选字段
            let id = try container.decodeIfPresent(String.self, forKey: .Id)
            let name = try container.decodeIfPresent(String.self, forKey: .Name)
            let locationType = try container.decodeIfPresent(String.self, forKey: .locationType)
            let state = try container.decodeIfPresent(String.self, forKey: .state)
            let language = try container.decodeIfPresent(String.self, forKey: .language)
            let pinCode = try container.decodeIfPresent(String.self, forKey: .pinCode)
            self = .national(id: id, name: name, locationType: locationType, state: state, language: language, pinCode: pinCode)
        }
    }
}

3. 配合上层结构体解码

如果上层的Place、Details等结构体需要解码,直接定义并包含Destination类型属性即可:

struct Place: Decodable, Equatable {
    let destination: Destination
    let package: Double
    let description: String
}

struct Details: Decodable, Equatable {
    let Attachments: [String]
    let place: Place
}

struct RootResponse: Decodable, Equatable {
    let Details: Details
}

关键注意点

  • 所有可选字段必须用decodeIfPresent解析,避免因字段缺失导致解码失败
  • CodingKeys需包含所有可能出现的JSON字段,确保能从容器中取出对应值
  • 如果需要严格校验某些必填关联值(比如international类型必须有country),可在对应分支中添加判断,抛出自定义DecodingError

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:35:22