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

Swift中无法访问第三方枚举实现时,优雅映射JSON字符串到枚举的方法

替代冗长Switch实现第三方枚举的JSON解码

问题场景

现有JSON数据:

{
  "title": "Some title",
  "subtitle": "Some subtitle",
  "button_type": "rounded"
}

当前解码逻辑中,ButtonType是来自第三方库的枚举,无法修改其源码让它遵守Codable协议,只能通过switch语句做字符串到枚举的映射:

// 该枚举来自第三方库,无法访问其实现代码
enum ButtonType {
    case squared
    case simple
    case rounded
    case normal
}

struct ResponseModel: Decodable {
    var title: String
    var subtitle: String
    var type: ButtonType
    
    enum CodingKeys: String, CodingKey {
        case title = "title"
        case subtitle = "subtitle"
        case type = "button_type"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        title = try container.decode(String.self, forKey: .title)
        subtitle = try container.decode(String.self, forKey: .subtitle)
        let stringType = try container.decode(String.self, forKey: .type)
        switch stringType {
        case "squared":
            type = .squared
        case "simple":
            type = .simple
        case "rounded":
            type = .rounded
        default:
            type = .normal
        }
    }
}

想要替代这段冗长的switch,用更优雅的方式实现映射。

可行的优雅方案

方案一:用映射字典集中管理

把字符串和枚举的对应关系放到一个静态字典里,直接通过字典查找获取枚举值,代码更简洁,后续修改映射也更方便:

struct ResponseModel: Decodable {
    var title: String
    var subtitle: String
    var type: ButtonType
    
    enum CodingKeys: String, CodingKey {
        case title, subtitle, type = "button_type"
    }
    
    // 集中管理字符串到枚举的映射
    private static let buttonTypeMap: [String: ButtonType] = [
        "squared": .squared,
        "simple": .simple,
        "rounded": .rounded
    ]
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        title = try container.decode(String.self, forKey: .title)
        subtitle = try container.decode(String.self, forKey: .subtitle)
        let stringType = try container.decode(String.self, forKey: .type)
        // 字典查找,找不到就用默认的.normal
        type = Self.buttonTypeMap[stringType] ?? .normal
    }
}

方案二:给枚举加扩展封装解析逻辑

把解析逻辑封装到ButtonType的扩展里,让ResponseModel的解码代码更清爽,同时解析逻辑可以复用:

// 给第三方枚举加扩展,封装解析方法
extension ButtonType {
    static func parse(from rawValue: String) -> ButtonType {
        switch rawValue {
        case "squared": return .squared
        case "simple": return .simple
        case "rounded": return .rounded
        default: return .normal
        }
    }
}

struct ResponseModel: Decodable {
    var title: String
    var subtitle: String
    var type: ButtonType
    
    enum CodingKeys: String, CodingKey {
        case title, subtitle, type = "button_type"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        title = try container.decode(String.self, forKey: .title)
        subtitle = try container.decode(String.self, forKey: .subtitle)
        let stringType = try container.decode(String.self, forKey: .type)
        // 直接调用扩展方法解析
        type = ButtonType.parse(from: stringType)
    }
}

方案三:用辅助解码类型封装逻辑

创建一个遵守Decodable的辅助类型,专门负责ButtonType的解码,让ResponseModel的职责更单一:

// 辅助解码类型,专门处理ButtonType的解码
private struct ButtonTypeDecoder: Decodable {
    let type: ButtonType
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let rawValue = try container.decode(String.self)
        type = [
            "squared": ButtonType.squared,
            "simple": .simple,
            "rounded": .rounded
        ][rawValue] ?? .normal
    }
}

struct ResponseModel: Decodable {
    var title: String
    var subtitle: String
    var type: ButtonType
    
    enum CodingKeys: String, CodingKey {
        case title, subtitle, type = "button_type"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        title = try container.decode(String.self, forKey: .title)
        subtitle = try container.decode(String.self, forKey: .subtitle)
        // 解码辅助类型,再取出枚举值
        let decoder = try container.decode(ButtonTypeDecoder.self, forKey: .type)
        type = decoder.type
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:07:23