I have JSON as below.
{
"type": "regular",
"data": [
{
"title": "Title 1",
"price_regular": 1.1,
"price_express": 2.2,
},
{
"title": "Title 2",
"price_regular": 1.1,
"price_express": 2.2,
}
]
}
For this I have model as below.
struct MainModel : Codable {
var type : String?
var data : [DataModel]?
}
struct DataModel : Codable {
var title : String?
var price_regular : Float?
var price_express : Float?
var price : Float {
get {
if (type == "regular") { ----> Please check below query for this.
return price_regular ?? 0.0
}
return price_express ?? 0.0
}
}
}
What I am doing in DataModel
is create new variable as price
. I want to check what data I have for type
of main class and based on that I want to get value for Price. Is there way I can achieve this?
Actually I am playing in model. I know I can make this run-time, but I would like to do this in model so that logic is at 1 place only.
CodePudding user response:
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
CodePudding user response:
With help of @Larme answer, I updated model and made it working.
struct MainModel : Codable {
var type : String?
var data : [DataModel]? {
didSet { // on didSet assigned value of type to type
for i in 0..<(self.data ?? [DataModel]()).count {
self.data![i].type = self.type ?? ""
}
}
}
}
struct DataModel : Codable {
var title : String?
var price_regular : Float?
var price_express : Float?
var type : String? // added new variable
var price : Float? {
get {
if (type == "regular") {
return price_regular ?? 0.0
}
return price_express ?? 0.0
}
}
}
And this helped me of doing what I was looking for...