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

Swift 4中Codable枚举遇未知字符串反序列化失败问题求助

解决Swift枚举Codable反序列化未知值失败的问题

这个问题我之前也踩过坑!Swift自动为String类型的Codable枚举生成的反序列化逻辑会严格匹配每个case的rawValue,一旦遇到未定义的字符串就会抛出DecodingError.dataCorrupted错误,导致整个反序列化失败。要解决这个问题,我们需要手动实现自定义的Codable逻辑,让未知值能被优雅地映射到unknown case。

方案一:简单容错(不保留未知值)

如果不需要保留那个未知的字符串,只需要让反序列化不崩溃,直接把未知值映射到unknown case即可。修改你的枚举如下:

enum Type: String, Codable {
    case text = "text"
    case image = "image"
    case document = "document"
    case profile = "profile"
    case sign = "sign"
    case inputDate = "input_date"
    case inputText = "input_text"
    case inputNumber = "input_number"
    case inputOption = "input_option"
    case unknown
    
    // 自定义反序列化逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let rawValue = try container.decode(String.self)
        // 尝试用rawValue初始化枚举,失败则 fallback 到unknown
        self = Type(rawValue: rawValue) ?? .unknown
    }
    
    // 可选:自定义编码逻辑(如果需要把unknown编码回去)
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .unknown:
            // 这里可以选择编码为"unknown",或者根据需求抛出错误/忽略
            try container.encode("unknown")
        default:
            try container.encode(self.rawValue)
        }
    }
}

原理很简单:先解码出JSON里的字符串值,然后尝试用init(rawValue:)创建枚举实例,要是失败就直接用unknown case,这样就不会崩溃了。

方案二:保留未知值(关联值存储)

如果你需要后续能拿到那个未知的字符串(比如做日志或者兼容处理),可以把unknown改成带关联值的case,把未知的rawValue存起来:

enum Type: Codable {
    case text
    case image
    case document
    case profile
    case sign
    case inputDate
    case inputText
    case inputNumber
    case inputOption
    case unknown(String)
    
    // 自定义rawValue映射
    var rawValue: String {
        switch self {
        case .text: return "text"
        case .image: return "image"
        case .document: return "document"
        case .profile: return "profile"
        case .sign: return "sign"
        case .inputDate: return "input_date"
        case .inputText: return "input_text"
        case .inputNumber: return "input_number"
        case .inputOption: return "input_option"
        case .unknown(let value): return value
        }
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let rawValue = try container.decode(String.self)
        // 逐个匹配已知的rawValue,不匹配就存到unknown的关联值里
        switch rawValue {
        case "text": self = .text
        case "image": self = .image
        case "document": self = .document
        case "profile": self = .profile
        case "sign": self = .sign
        case "input_date": self = .inputDate
        case "input_text": self = .inputText
        case "input_number": self = .inputNumber
        case "input_option": self = .inputOption
        default: self = .unknown(rawValue)
        }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        // 编码时直接用对应的rawValue,包括未知值
        try container.encode(rawValue)
    }
}

这种方式不仅能让反序列化不崩溃,还能保留那个未知的字符串,后续你可以通过if case .unknown(let value) = type来取出这个值做处理。

测试验证

你可以用下面的代码测试一下效果:

// 包含未知值的JSON
let json = """
{"type": "custom_unknown_type"}
"""

struct TestModel: Codable {
    let type: Type
}

do {
    let model = try JSONDecoder().decode(TestModel.self, from: json.data(using: .utf8)!)
    print(model.type)
    // 方案一输出:unknown
    // 方案二输出:unknown("custom_unknown_type")
} catch {
    print("反序列化失败:\(error)")
}

这样修改后,遇到任何未定义的字符串都不会导致反序列化失败了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:34:45