I'd do it with a custom init(from decoder:)
, allowing to pass type from MainModel
to DataModel
.
struct MainModel : Codable {
var type : String?
var data : [DataModel]?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
type = try container.decode(String.self, forKey: .type)
var dataContainer = try container.nestedUnkeyedContainer(forKey: .data)
var dataTemp: [DataModel] = []
while !dataContainer.isAtEnd {
let dataSubcontainer = try dataContainer.nestedContainer(keyedBy: DataModel.DataModelKeys.self)
let title = try dataSubcontainer.decode(String.self, forKey: .title)
let price_regular = try dataSubcontainer.decode(Float.self, forKey: .price_regular)
let price_express = try dataSubcontainer.decode(Float.self, forKey: .price_express)
dataTemp.append(DataModel(title: title, price_regular: price_regular, price_express: price_express, type: type))
}
data = dataTemp
}
}
struct DataModel : Codable {
var title : String?
var price_regular : Float?
var price_express : Float?
var type: String?
enum DataModelKeys: String, CodingKey {
case title
case price_regular
case price_express
}
var price : Float {
get {
if (type == "regular") {
return price_regular ?? 0.0
}
return price_express ?? 0.0
}
}
}
To test it:
let json = """
[{
"type": "regular",
"data": [
{
"title": "Title 1",
"price_regular": 1.1,
"price_express": 1.2,
},
{
"title": "Title 2",
"price_regular": 2.1,
"price_express": 2.2,
}
]
},
{
"type": "irregular",
"data": [
{
"title": "Title 3",
"price_regular": 1.1,
"price_express": 1.2,
},
{
"title": "Title 4",
"price_regular": 2.1,
"price_express": 2.2,
}
]
}]
"""
do {
let model = try JSONDecoder().decode([MainModel].self, from: Data(json.utf8))
print(model)
model.forEach { aMainModel in
print("MainModel type: \(aMainModel.type)")
aMainModel.data?.forEach {
print("Title: \($0.title) - type: \($0.type) - price: \($0.price)")
}
}
} catch {
print("Error: \(error)")
}
Which output:
$>MainModel type: Optional("regular")
$>Title: Optional("Title 1") - type: Optional("regular") - price: 1.1
$>Title: Optional("Title 2") - type: Optional("regular") - price: 2.1
$>MainModel type: Optional("irregular")
$>Title: Optional("Title 3") - type: Optional("irregular") - price: 1.2
$>Title: Optional("Title 4") - type: Optional("irregular") - price: 2.2