Swift Codable 多种类型

Posted

技术标签:

【中文标题】Swift Codable 多种类型【英文标题】:Swift Codable multiple types 【发布时间】:2019-03-11 21:24:31 【问题描述】:

我尝试解析返回 json 对象的 api。我的问题是某些键有时是字符串,有时是对象,例如以下示例中的键“Value”:

[

    "Description": null,
    "Group": "Beskrivning av enheten",
    "GroupDescription": null,
    "Id": "Description",
    "Name": "Mer om enheten",
    "Value": "Det finns möjlighet till parkering på gatorna runt om, men det är kantstenar och ganska branta backar för att komma upp till lekplatsen.\r\n\r\nUtanför själva lekplatsen finns en gungställning med en plan omväg in. Alla lekredskap står i sandytor, det finns många kanter. Runt hela lekplatsen går ett staket med öppningar i olika riktningar."
,

    "Description": null,
    "Group": "Bilder och film",
    "GroupDescription": null,
    "Id": "Image",
    "Name": "Huvudbild",
    "Value": 
        "__type": "FileInfo",
        "Id": "8871b3b1-14f4-4054-8728-636d9da21ace",
        "Name": "ullerudsbacken.jpg"
    

]

我的结构如下所示:

struct ServiceUnit: Codable 
        let description: String?
        let group: String?
        let groupDescription: String?
        let id: String
        let name: String
        var value: String?
        struct ServiceUnitTypeInfo: Codable 
            let id: String
            let singularName: String?
            enum CodingKeys: String, CodingKey 
                case id = "Id"
                case singularName = "SingularName"
            
        
        let serviceUnitTypeInfo: ServiceUnitTypeInfo?
        let values: [String]?
        enum CodingKeys: String, CodingKey 
            case description = "Description"
            case group = "Group"
            case groupDescription = "GroupDescription"
            case id = "Id"
            case name = "Name"
            case value = "Value"
            case serviceUnitTypeInfo = "ServiceUnitTypeInfo"
            case values = "Values"
            case image = "Image"
        
    

我必须管理我完全迷失了(是的,我是 swift 的初学者)并且我找不到解决问题的方法。我知道我必须使用自定义初始化,但我不知道如何。

【问题讨论】:

【参考方案1】:

你可以试试

struct Root: Codable 
    let description,id: String
    let group,groupDescription: String?
    let name: String
    let value: MyValue

    enum CodingKeys: String, CodingKey 
        case description = "Description"
        case group = "Group"
        case groupDescription = "GroupDescription"
        case id = "Id"
        case name = "Name"
        case value = "Value"
    


enum MyValue: Codable 
    case string(String)
    case innerItem(InnerItem)

    init(from decoder: Decoder) throws 
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) 
            self = .string(x)
            return
        
        if let x = try? container.decode(InnerItem.self) 
            self = .innerItem(x)
            return
        
        throw DecodingError.typeMismatch(MyValue.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
    

    func encode(to encoder: Encoder) throws 
        var container = encoder.singleValueContainer()
        switch self 
        case .string(let x):
            try container.encode(x)
        case .innerItem(let x):
            try container.encode(x)
        
    


struct InnerItem: Codable 
    let type, id, name: String

    enum CodingKeys: String, CodingKey 
        case type = "__type"
        case id = "Id"
        case name = "Name"
    


do 
  let result = try JSONDecoder().decode([Root].self,from:data)
  print(result)

catch 
  print(error)

【讨论】:

当我尝试访问“value”的值以在 label.text 中使用它时,我收到错误“无法分配类型为 'MyValue?' 的值?”键入“字符串?”。当我将值打印到终端时,它会显示 ... unknown context at 0x109d06188).MyValue.string ... 你知道我该如何解决这个问题吗? @Sylvain 这可能是因为它是枚举,而不是字符串值。 如何从变量值中获取价值?每当我尝试打印值时,它都会显示 MyValue.string("value") MyValue.string("value"),什么是 "Value" ,这正是我们将值传递给枚举的内容,但在此之前我们需要获取该特定值。【参考方案2】:

基于@Sh_Khan 的回答并回答 cmets 中@Nikhi 的问题(如何访问这些值),我喜欢将其添加到枚举声明中:

var innerItemValue: InnerItem? 
    switch self 
    case .innerItem(let ii):
        return ii
    default:
        return nil
    


var stringValue: String? 
    switch self 
    case .string(let s):
        return s
    default:
        return nil
    

【讨论】:

你能告诉我把这段代码放在哪里吗? @gudio 在枚举声明中 非常感谢@guido。现在我可以获取值了。 @guido 如何手动为其设置值,例如 Root.value = 1 ?

以上是关于Swift Codable 多种类型的主要内容,如果未能解决你的问题,请参考以下文章

Swift Codable: 服务端新增枚举类型解析失败?

Swift Codable: 服务端新增枚举类型解析失败?

Swift 根据响应类型为 JSON 字段值动态选择 Codable 结构

Swift4 中的 Codable 和 XMLParser

Swift之Codable自定义解析将任意数据类型解析为想要的类型

Swift之Codable自定义解析将任意数据类型解析为想要的类型