Возможно, у вас есть следующий класс, описывающий корень вашего 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
и 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
:
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:
enum Pointable {
case conferenceInterestPoint(ConferenceInterestPoint?)
case restaurantInterestPoint(RestaurantInterestPoint?)
}
В такихВ случае, если вы получите следующее InterestPoint
:
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.