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

