繁体   English   中英

单个JSON返回值中有多种可编码对象类型

[英]Multiple codable object types out of a single JSON return

我的困境是我从JSON响应的一个表中接收了两种不同的对象类型。 这是返回中两种类型的响应的示例。

"supplementaryItems": [
    {
        "header": "Doodle",
        "subHeader": "It's a drawing.",
        "slideID": 4,
        "imageName": null,
        "textItems": null,
        "sortOrder": 0
    },
    {
        "header": "Cell Phones",
        "subHeader": "No phones please",
        "slideID": 8,
        "imageName": "welcome_icon_cellphones",
        "textItems": ["first","second","third"],
        "sortOrder": 1
    }
]

我们希望做的是在这里创建两种不同类型的对象。 一个textOnlyItem和一个imageWithTextItem

有没有一种方法可以将其创建为可以通过imageName是否为null定义的Bool禁用的子类或扩展?

谢谢大家的帮助。

您不需要两个不同的对象。 只需将imageNametextItems声明为可选,即可处理null情况。

您可以简单地检查imageName是否为nil

let jsonString = """
{"supplementaryItems": [
{
"header": "Doodle",
"subHeader": "It's a drawing.",
"slideID": 4,
"imageName": null,
"textItems": null,
"sortOrder": 0
},
{
"header": "Cell Phones",
"subHeader": "No phones please",
"slideID": 8,
"imageName": "welcome_icon_cellphones",
"textItems": ["first","second","third"],
"sortOrder": 1
}
]
}
"""

struct Root : Decodable {
    let supplementaryItems : [SupplementaryItem]
}

struct SupplementaryItem : Decodable {
    let header : String
    let subHeader : String
    let slideID : Int
    let imageName : String?
    let textItems : [String]?
    let sortOrder : Int
}

do {
    let data = Data(jsonString.utf8)
    let result = try JSONDecoder().decode(Root.self, from: data)
    for item in result.supplementaryItems {
       if let imageName = item.imageName {
           print(imageName + " has text items")
       } else {
           print(item.header + " has no text items")
       }
    }
} catch { print(error) }

我实际上喜欢vadian的一种方法。 但我认为这将需要对您的情况进行重大重构。

另一种方法是仅使用JSONSerialization并手动构建异构数组。 JSONSerialization并没有被弃用,只是没有像JSONDecoder这样自动JSONDecoder

另一种方法是使用JSONDecoder ,编写尝试将其解码为ImageItem自定义初始化程序,如果失败,请尝试将其解码为TextItem

protocol SupplementaryItem {
    var header:    String    { get }
    var subHeader: String    { get }
    var slideID:   Int       { get }
    var sortOrder: Int       { get }
    var textItems: [String]? { get }
}

struct TextItem: SupplementaryItem, Codable {
    let header:    String
    let subHeader: String
    let slideID:   Int
    let sortOrder: Int
    let textItems: [String]?
}

struct ImageItem: SupplementaryItem, Codable {
    let header:    String
    let subHeader: String
    let slideID:   Int
    let sortOrder: Int
    let textItems: [String]?
    let imageName: String
}

struct ResponseObject: Decodable {
    let supplementaryItems: [SupplementaryItem]

    enum CodingKeys: String, CodingKey {
        case supplementaryItems
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        var container = try values.nestedUnkeyedContainer(forKey: .supplementaryItems)
        if container.count == nil {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Expected array for supplementaryItems")
        }
        var items = [SupplementaryItem]()
        while !container.isAtEnd {
            if let item = try? container.decodeIfPresent(ImageItem.self), let imageItem = item {
                items.append(imageItem)
            } else {
                let textItem = try container.decode(TextItem.self)
                items.append(textItem)
            }
        }
        supplementaryItems = items
    }
}

然后:

let string = """
    {
        "supplementaryItems": [
            {
                "header": "Doodle",
                "subHeader": "It's a drawing.",
                "slideID": 4,
                "imageName": "foo",
                "textItems": null,
                "sortOrder": 0
            },
            {
                "header": "Cell Phones",
                "subHeader": "No phones please",
                "slideID": 8,
                "imageName": "welcome_icon_cellphones",
                "textItems": ["first","second","third"],
                "sortOrder": 1
            }
        ]
    }
    """

let data = string.data(using: .utf8)!

let json = try! JSONDecoder().decode(ResponseObject.self, from: data)
print(json)

我不相信这比仅使用JSONSerialization更好或更糟,但这是另一种方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM