快速解码多态json响应

快速解码多态json响应,json,inheritance,polymorphism,swift4,codable,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,

你好,我想解码这个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": [],
}

“pointable”字段是一个感兴趣的子类,其类型取决于“pointable”类型。我想动态地将响应解码为感兴趣的good ChildType point

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

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)
    }
}
我猜您有
BaseInterestPoint
作为
InterestPoint
ConferenceInterestPoint
restaurantinterespoint
的基类:

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)
    }
}
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)
    }
}
final class InterestPoint: BaseInterestPoint {
    let name: String?
    let description: String?
    let pointableType: String?
    let pointableId: Int?
    let workingTime: [Int]?
    let pointable: Pointable?
    let comments: [String]?

    private enum CodingKeys: String, CodingKey {
        case name
        case description
        case pointableType = "pointable_type"
        case pointableId = "pointable_id"
        case workingTime = "working_time"
        case pointable
        case comments
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        pointableType = try values.decodeIfPresent(String.self, forKey: .pointableType)
        pointableId = try values.decodeIfPresent(Int.self, forKey: .pointableId)
        workingTime = try values.decodeIfPresent([Int].self, forKey: .workingTime)
        if pointableType == "ConferenceInterestPoint" {
            pointable = .conferenceInterestPoint(try values.decodeIfPresent(ConferenceInterestPoint.self, forKey: .pointable))
        } else if pointableType == "RestaurantInterestPoint" {
            pointable = .restaurantInterestPoint(try values.decodeIfPresent(RestaurantInterestPoint.self, forKey: .pointable))
        } else {
            pointable = nil
        }
        comments = try values.decodeIfPresent([String].self, forKey: .comments)
        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(name, forKey: .name)
        try container.encode(description, forKey: .description)
        try container.encode(pointableType, forKey: .pointableType)
        try container.encode(pointableId, forKey: .pointableId)
        try container.encode(workingTime, forKey: .workingTime)
        if let pointable = pointable {
            switch pointable {
            case .conferenceInterestPoint(let conferenceInterestPoint):
                if let conferenceInterestPoint = conferenceInterestPoint {
                    try container.encode(conferenceInterestPoint, forKey: .pointable)
                }
            case .restaurantInterestPoint(let restaurantInterestPoint):
                if let restaurantInterestPoint = restaurantInterestPoint {
                    try container.encode(restaurantInterestPoint, forKey: .pointable)
                }
            }
        }
        try container.encode(comments, forKey: .comments)
    }
}
会议兴趣点
餐厅兴趣点

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)
    }
}
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)
    }
}
final class InterestPoint: BaseInterestPoint {
    let name: String?
    let description: String?
    let pointableType: String?
    let pointableId: Int?
    let workingTime: [Int]?
    let pointable: Pointable?
    let comments: [String]?

    private enum CodingKeys: String, CodingKey {
        case name
        case description
        case pointableType = "pointable_type"
        case pointableId = "pointable_id"
        case workingTime = "working_time"
        case pointable
        case comments
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        pointableType = try values.decodeIfPresent(String.self, forKey: .pointableType)
        pointableId = try values.decodeIfPresent(Int.self, forKey: .pointableId)
        workingTime = try values.decodeIfPresent([Int].self, forKey: .workingTime)
        if pointableType == "ConferenceInterestPoint" {
            pointable = .conferenceInterestPoint(try values.decodeIfPresent(ConferenceInterestPoint.self, forKey: .pointable))
        } else if pointableType == "RestaurantInterestPoint" {
            pointable = .restaurantInterestPoint(try values.decodeIfPresent(RestaurantInterestPoint.self, forKey: .pointable))
        } else {
            pointable = nil
        }
        comments = try values.decodeIfPresent([String].self, forKey: .comments)
        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(name, forKey: .name)
        try container.encode(description, forKey: .description)
        try container.encode(pointableType, forKey: .pointableType)
        try container.encode(pointableId, forKey: .pointableId)
        try container.encode(workingTime, forKey: .workingTime)
        if let pointable = pointable {
            switch pointable {
            case .conferenceInterestPoint(let conferenceInterestPoint):
                if let conferenceInterestPoint = conferenceInterestPoint {
                    try container.encode(conferenceInterestPoint, forKey: .pointable)
                }
            case .restaurantInterestPoint(let restaurantInterestPoint):
                if let restaurantInterestPoint = restaurantInterestPoint {
                    try container.encode(restaurantInterestPoint, forKey: .pointable)
                }
            }
        }
        try container.encode(comments, forKey: .comments)
    }
}
要解决多态对象的问题,请使用枚举:

enum Pointable {
    case conferenceInterestPoint(ConferenceInterestPoint?)
    case restaurantInterestPoint(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)
    }
}
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)
    }
}
final class InterestPoint: BaseInterestPoint {
    let name: String?
    let description: String?
    let pointableType: String?
    let pointableId: Int?
    let workingTime: [Int]?
    let pointable: Pointable?
    let comments: [String]?

    private enum CodingKeys: String, CodingKey {
        case name
        case description
        case pointableType = "pointable_type"
        case pointableId = "pointable_id"
        case workingTime = "working_time"
        case pointable
        case comments
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        pointableType = try values.decodeIfPresent(String.self, forKey: .pointableType)
        pointableId = try values.decodeIfPresent(Int.self, forKey: .pointableId)
        workingTime = try values.decodeIfPresent([Int].self, forKey: .workingTime)
        if pointableType == "ConferenceInterestPoint" {
            pointable = .conferenceInterestPoint(try values.decodeIfPresent(ConferenceInterestPoint.self, forKey: .pointable))
        } else if pointableType == "RestaurantInterestPoint" {
            pointable = .restaurantInterestPoint(try values.decodeIfPresent(RestaurantInterestPoint.self, forKey: .pointable))
        } else {
            pointable = nil
        }
        comments = try values.decodeIfPresent([String].self, forKey: .comments)
        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(name, forKey: .name)
        try container.encode(description, forKey: .description)
        try container.encode(pointableType, forKey: .pointableType)
        try container.encode(pointableId, forKey: .pointableId)
        try container.encode(workingTime, forKey: .workingTime)
        if let pointable = pointable {
            switch pointable {
            case .conferenceInterestPoint(let conferenceInterestPoint):
                if let conferenceInterestPoint = conferenceInterestPoint {
                    try container.encode(conferenceInterestPoint, forKey: .pointable)
                }
            case .restaurantInterestPoint(let restaurantInterestPoint):
                if let restaurantInterestPoint = restaurantInterestPoint {
                    try container.encode(restaurantInterestPoint, forKey: .pointable)
                }
            }
        }
        try container.encode(comments, forKey: .comments)
    }
}

本文中的所有代码都是在Xcode 10.2.1中测试的。

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

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)
    }
}
我猜您有
BaseInterestPoint
作为
InterestPoint
ConferenceInterestPoint
restaurantinterespoint
的基类:

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)
    }
}
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)
    }
}
final class InterestPoint: BaseInterestPoint {
    let name: String?
    let description: String?
    let pointableType: String?
    let pointableId: Int?
    let workingTime: [Int]?
    let pointable: Pointable?
    let comments: [String]?

    private enum CodingKeys: String, CodingKey {
        case name
        case description
        case pointableType = "pointable_type"
        case pointableId = "pointable_id"
        case workingTime = "working_time"
        case pointable
        case comments
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        pointableType = try values.decodeIfPresent(String.self, forKey: .pointableType)
        pointableId = try values.decodeIfPresent(Int.self, forKey: .pointableId)
        workingTime = try values.decodeIfPresent([Int].self, forKey: .workingTime)
        if pointableType == "ConferenceInterestPoint" {
            pointable = .conferenceInterestPoint(try values.decodeIfPresent(ConferenceInterestPoint.self, forKey: .pointable))
        } else if pointableType == "RestaurantInterestPoint" {
            pointable = .restaurantInterestPoint(try values.decodeIfPresent(RestaurantInterestPoint.self, forKey: .pointable))
        } else {
            pointable = nil
        }
        comments = try values.decodeIfPresent([String].self, forKey: .comments)
        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(name, forKey: .name)
        try container.encode(description, forKey: .description)
        try container.encode(pointableType, forKey: .pointableType)
        try container.encode(pointableId, forKey: .pointableId)
        try container.encode(workingTime, forKey: .workingTime)
        if let pointable = pointable {
            switch pointable {
            case .conferenceInterestPoint(let conferenceInterestPoint):
                if let conferenceInterestPoint = conferenceInterestPoint {
                    try container.encode(conferenceInterestPoint, forKey: .pointable)
                }
            case .restaurantInterestPoint(let restaurantInterestPoint):
                if let restaurantInterestPoint = restaurantInterestPoint {
                    try container.encode(restaurantInterestPoint, forKey: .pointable)
                }
            }
        }
        try container.encode(comments, forKey: .comments)
    }
}
会议兴趣点
餐厅兴趣点

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)
    }
}
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)
    }
}
final class InterestPoint: BaseInterestPoint {
    let name: String?
    let description: String?
    let pointableType: String?
    let pointableId: Int?
    let workingTime: [Int]?
    let pointable: Pointable?
    let comments: [String]?

    private enum CodingKeys: String, CodingKey {
        case name
        case description
        case pointableType = "pointable_type"
        case pointableId = "pointable_id"
        case workingTime = "working_time"
        case pointable
        case comments
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        pointableType = try values.decodeIfPresent(String.self, forKey: .pointableType)
        pointableId = try values.decodeIfPresent(Int.self, forKey: .pointableId)
        workingTime = try values.decodeIfPresent([Int].self, forKey: .workingTime)
        if pointableType == "ConferenceInterestPoint" {
            pointable = .conferenceInterestPoint(try values.decodeIfPresent(ConferenceInterestPoint.self, forKey: .pointable))
        } else if pointableType == "RestaurantInterestPoint" {
            pointable = .restaurantInterestPoint(try values.decodeIfPresent(RestaurantInterestPoint.self, forKey: .pointable))
        } else {
            pointable = nil
        }
        comments = try values.decodeIfPresent([String].self, forKey: .comments)
        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(name, forKey: .name)
        try container.encode(description, forKey: .description)
        try container.encode(pointableType, forKey: .pointableType)
        try container.encode(pointableId, forKey: .pointableId)
        try container.encode(workingTime, forKey: .workingTime)
        if let pointable = pointable {
            switch pointable {
            case .conferenceInterestPoint(let conferenceInterestPoint):
                if let conferenceInterestPoint = conferenceInterestPoint {
                    try container.encode(conferenceInterestPoint, forKey: .pointable)
                }
            case .restaurantInterestPoint(let restaurantInterestPoint):
                if let restaurantInterestPoint = restaurantInterestPoint {
                    try container.encode(restaurantInterestPoint, forKey: .pointable)
                }
            }
        }
        try container.encode(comments, forKey: .comments)
    }
}
要解决多态对象的问题,请使用枚举:

enum Pointable {
    case conferenceInterestPoint(ConferenceInterestPoint?)
    case restaurantInterestPoint(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)
    }
}
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)
    }
}
final class InterestPoint: BaseInterestPoint {
    let name: String?
    let description: String?
    let pointableType: String?
    let pointableId: Int?
    let workingTime: [Int]?
    let pointable: Pointable?
    let comments: [String]?

    private enum CodingKeys: String, CodingKey {
        case name
        case description
        case pointableType = "pointable_type"
        case pointableId = "pointable_id"
        case workingTime = "working_time"
        case pointable
        case comments
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        pointableType = try values.decodeIfPresent(String.self, forKey: .pointableType)
        pointableId = try values.decodeIfPresent(Int.self, forKey: .pointableId)
        workingTime = try values.decodeIfPresent([Int].self, forKey: .workingTime)
        if pointableType == "ConferenceInterestPoint" {
            pointable = .conferenceInterestPoint(try values.decodeIfPresent(ConferenceInterestPoint.self, forKey: .pointable))
        } else if pointableType == "RestaurantInterestPoint" {
            pointable = .restaurantInterestPoint(try values.decodeIfPresent(RestaurantInterestPoint.self, forKey: .pointable))
        } else {
            pointable = nil
        }
        comments = try values.decodeIfPresent([String].self, forKey: .comments)
        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(name, forKey: .name)
        try container.encode(description, forKey: .description)
        try container.encode(pointableType, forKey: .pointableType)
        try container.encode(pointableId, forKey: .pointableId)
        try container.encode(workingTime, forKey: .workingTime)
        if let pointable = pointable {
            switch pointable {
            case .conferenceInterestPoint(let conferenceInterestPoint):
                if let conferenceInterestPoint = conferenceInterestPoint {
                    try container.encode(conferenceInterestPoint, forKey: .pointable)
                }
            case .restaurantInterestPoint(let restaurantInterestPoint):
                if let restaurantInterestPoint = restaurantInterestPoint {
                    try container.encode(restaurantInterestPoint, forKey: .pointable)
                }
            }
        }
        try container.encode(comments, forKey: .comments)
    }
}

这篇文章中的所有代码都是在Xcode 10.2.1中测试的。

在我的回答中,我添加了一些类,因为您的问题中没有提供任何代码。我是否正确理解你的应用程序中有哪些类?在我的回答中,我添加了一些类,因为你没有在问题中提供任何代码。我是否正确理解你的应用程序中有哪些类?