如何在json中使用Codable解析数据有键但值与枚举不匹配

Posted

技术标签:

【中文标题】如何在json中使用Codable解析数据有键但值与枚举不匹配【英文标题】:How to parse data with Codable in json has key but value not match with enum any case 【发布时间】:2018-06-18 07:08:26 【问题描述】:

我已经创建了一个如下所示的模型,其中包含一个用于性别的自定义枚举

enum Gender :String, Codable 
    case male = "Male"
    case female = "Female"


class Person : Codable 
    var name : String?
    var gender : Gender?

    convenience init(name : String, gender : Gender) 
        self.init()
        self.name = name
        self.gender = gender
    

    enum CodingKeys: String, CodingKey 

        case name    = "name"
        case gender  = "gender"

    

以下是我从 API 获取的 json 数据

[
  
    "name": "name1",
    "gender": "Male"
  ,
  
    "name": "name2",
    "gender": "Male"
  
]

如果我使用以下代码解析数据,则在响应的成功块中它工作正常

  do 

        let list = try JSONDecoder().decode([Person].self, from: data)

        print("list \(list)")

    
    catch 
        print("error \(error)")
    

现在的问题是,如果在响应 api 中以所有小写 like "gender": "male" 提供性别,则解析不起作用并给出以下错误。

error dataCorrupted(Swift.DecodingError.Context(codingPath: 
[_JSONKey(stringValue: "Index 1", intValue: 1), CodingKeys(stringValue:
"gender", intValue: nil)], debugDescription: "Cannot initialize Gender from
 invalid String value male", underlyingError: nil))

我想要下面的任何一种解决方案

要么解析数据忽略枚举的大小写值 创建对象 性别为零的人,因为它与任何情况都不匹配

还有一件事我不想覆盖编码器和解码器方法,因为我的实际项目中有很多参数。我已经意识到这一点。

【问题讨论】:

如果您使用JSONDecoder 来填充模型对象,如果您不想使用默认行为,则必须覆盖解码器方法。另外,“我的实际项目中有我的参数”是什么意思。 Swift 枚举区分大小写。您无法解析“男性”,它应该是“男性”。 【参考方案1】:

您可以通过为Person 覆盖init(from decoder:) 来做到这一点...

enum Gender :String, Codable 
    case male, female // Note that I removed the uppercase string values 


struct Person : Codable 
    var name : String?
    var gender : Gender?

    enum CodingKeys: String, CodingKey 
        case name, gender // No need for string values if they match the enum cases
    

    init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decodeIfPresent(String.self, forKey: .name) // decodeIfPresent as name is optional 

        let genderString = try container.decode(String.self, forKey: .gender)
        gender = Gender(rawValue: genderString.lowercased()) // This is why I removed the uppercase String values
    

【讨论】:

以上是关于如何在json中使用Codable解析数据有键但值与枚举不匹配的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Codable 在 Swift 中使用动态文件名解析 JSON

使用 Codable 解析嵌套的 JSON 数据

使用 Codable 解析 JSON 数据

如何使用 Codable 和 Swift 解析这个嵌套的 JSON?

使用 Codable 解析嵌套 JSON 数据问题

使用 Codable 解析多级 JSON