【问题标题】:how to get data based on the previous level data如何根据上一级数据获取数据
【发布时间】:2022-01-16 21:27:05
【问题描述】:

我有如下 JSON。

{
  "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,
    }
  ]
}

为此,我有如下模型。

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
        }
    }
}

我在DataModel 中所做的是将新变量创建为price。我想检查我对主类type 有哪些数据,并在此基础上获得价格的价值。有什么办法可以做到这一点?

其实我是在做模特。我知道我可以使这个运行时,但我想在模型中执行此操作,以便逻辑仅在 1 个位置。

【问题讨论】:

  • 你不能。你可以给DataModel一个额外的属性type,它会让你知道价格。但这需要通过覆盖init(from decoder:) 来自定义解析(JSON)。为什么这被标记为 Android btw?
  • @Larme : 因为这种风格在 swift/android 中用得最多。所以考虑添加两个标签,否则只是模型不会更多地关注这个问题。另外我不做任何覆盖,因为上面的代码可以正常工作,但最重要的是我想知道如何访问前一个对象的变量。
  • @Larme :我所拥有的是交付类型,基于此我将显示价格。因此,我在模型和类型中添加新变量为 price,我只在 1 个地方定义...
  • 因为你是用 Swift 编写的,所以它与 Android 并没有真正的联系,因为语言给它带来了一些适当的逻辑,这就是为什么在我看来,Android 标签具有误导性。而且,它是一个操作系统,所以很奇怪。

标签: swift model


【解决方案1】:

我会使用自定义init(from decoder:) 来实现,允许将类型从MainModel 传递到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
        }
    }
}

测试它:

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)")
}

哪个输出:

$>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

【讨论】:

  • 谢谢,你的做法帮助了我,我用另一种方式做到了。稍后检查答案...
  • 可以看看this question of mine
【解决方案2】:

@Larme 回答的帮助下,我更新了模型并使其工作。

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
        }
    }
}

这帮助我完成了我一直在寻找的事情......

【讨论】:

  • 你确定你的代码有效吗?我试过了,但没有,因为不应该在 init 方法上调用 didSet。您可以使用我的示例对其进行测试,该示例具有类型值的两个可能值。 type of DataModel 每次都为零,因为没有设置。
  • 查看stackoverflow.com/questions/25230780/… 了解解决方法和文档链接
  • @Larme:我明白你的意思。一旦我从 API 获得数据,didSet 将不会被调用。当我实现 API 时,我会进一步检查。现在我正在使用 for 循环准备数据,这就是为什么这对我有用。
猜你喜欢
  • 2020-11-23
  • 2020-03-25
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 2017-12-19
  • 2021-07-23
  • 2014-12-17
  • 1970-01-01
相关资源
最近更新 更多