快速解码多态json响应

时间:2019-05-17 19:30:58

标签: json inheritance polymorphism swift4 codable

你好,我想解码这个json。

"interest_point":{
    "id": 2,
    "name": "Panoramic",
    "description": "On vous propose ....",
    "pointable_type": "ConferenceInterestPoint",
    "pointable_id": 1,
    "working_time": [],
    "pointable": {
        "id": 1,
        "surface": 354.56,
        "capacity": "140",
        "price": 500,
        "price_unit": "HOURS",
    },
    "comments": [],
}
"interest_point":{
    "id": 5,
    "name": "Carte",
    "description": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "pointable_type": "RestaurantInterestPoint",
    "pointable_id": 2,
    "working_time": [],
    "pointable": {
        "id": 2,
        "type": "CARTE",
        "smocking_area": 1,
    },
    "comments": []

}

“ pointable”字段是interest_point的子类,其类型取决于“ pointable_type”。我想动态地将响应解码为InterestPoint的良好ChildType

1 个答案:

答案 0 :(得分:0)

也许您有以下类描述了JSON的根:

rect

据我猜测,您有final class Root: Codable { let interestPoint: InterestPoint? private enum CodingKeys: String, CodingKey { case interestPoint = "interest_point" } required init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) interestPoint = try values.decodeIfPresent(InterestPoint.self, forKey: .interestPoint) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(interestPoint, forKey: .interestPoint) } } 作为BaseInterestPointInterestPointConferenceInterestPoint的基类:

RestaurantInterestPoint

class BaseInterestPoint: Codable { let id: Int? private enum CodingKeys: String, CodingKey { case id } required init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) id = try values.decodeIfPresent(Int.self, forKey: .id) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) } } ConferenceInterestPoint

RestaurantInterestPoint

要解决多态对象的问题,请使用enum:

final class ConferenceInterestPoint: BaseInterestPoint {
    let surface: Double?
    let capacity: String?
    let price: Int?
    let priceUnit: String?

    private enum CodingKeys: String, CodingKey {
        case surface
        case capacity
        case price
        case priceUnit = "price_unit"
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        surface = try values.decodeIfPresent(Double.self, forKey: .surface)
        capacity = try values.decodeIfPresent(String.self, forKey: .capacity)
        price = try values.decodeIfPresent(Int.self, forKey: .price)
        priceUnit = try values.decodeIfPresent(String.self, forKey: .priceUnit)
        try super.init(from: decoder)
    }

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(surface, forKey: .surface)
        try container.encode(capacity, forKey: .capacity)
        try container.encode(price, forKey: .price)
        try container.encode(priceUnit, forKey: .priceUnit)
    }
}

final class RestaurantInterestPoint: BaseInterestPoint {
    let type: String?
    let smockingArea: Int?

    private enum CodingKeys: String, CodingKey {
        case type
        case smockingArea = "smocking_area"
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        type = try values.decodeIfPresent(String.self, forKey: .type)
        smockingArea = try values.decodeIfPresent(Int.self, forKey: .smockingArea)
        try super.init(from: decoder)
    }

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(type, forKey: .type)
        try container.encode(smockingArea, forKey: .smockingArea)
    }
}

在这种情况下,您将获得以下enum Pointable { case conferenceInterestPoint(ConferenceInterestPoint?) case restaurantInterestPoint(RestaurantInterestPoint?) }

InterestPoint