【问题标题】:Decoding JSON and map it to existing object Swift解码 JSON 并将其映射到现有对象 Swift
【发布时间】:2020-02-10 07:21:43
【问题描述】:

我有以下对象

struct Properties: Decodable {
    var id: String?
    var value: String?
    var color: String?
}

在对服务器的第一个请求中,我得到以下响应

{ 
   "id":"1",
   "color":"red"
}

在另一个请求之后,我得到了

{ 
   "id":"1",  // the id of the object props is meant for 
   "props":{ 
      "value":"my value" // I can get any property here
   }
}

在两个请求之后,我应该设置所有属性的对象

现在我将第二个请求解码如下

struct SetAttr: Decodable {

    let id: String
    let props: [String : Any]

    enum SetAttrCodingKeys: String, CodingKey {
        case id
        case props
    }

    init(from decoder: Decoder) throws {

        let container = try! decoder.container(keyedBy: SetAttrCodingKeys.self)
        props = try! container.decode([String : Any].self, forKey: .props)
        id = try! container.decode(String.self, forKey: .id)

    }
}

但我不知道如何解析props 字典并在第一个对象上设置属性。我愿意使用解码库,但我没有找到任何可以做到这一点

编辑:

这就是我尝试从字典中设置属性的方式,但解决方案不可扩展

var myObject: Properties
properties = setAttr.props // [String:Any]

let keys = properties.keys

keys.forEach { key in

    if let value = properties[key] {

        switch key {
        case "value":
            myObject.value = value as? String
        case "color":
            myObject.color = value as? String
        default:
            break
        }
    }
}

【问题讨论】:

  • 如果您仍然需要两个步骤来创建和填充结构,我建议使用传统的JSONSerialization 解码props 请求。
  • 这个解决方案真的和json有关吗?
  • @vadian 好的,但是如何将它映射到前一个对象
  • Properties 中指定CodingKeys idcolor,并使用JSONDecoder 解码第一个响应。然后使用JSONSerialization 解码第二个响应并更新Properties 实例。

标签: ios json swift decodable


【解决方案1】:

只需使用 JSONSerialization 即可将您扔给它的任何内容解析为数组和字典。这使您摆脱了格式奇怪的 JSON 所带来的所有问题。

例如,第二个请求将被解析为具有两个键“id”和“props”的字典,而“props”的值又是一个具有一个键“value”和一个值“my value”的字典”。

请停止使用 try!如果不需要任何输入,这将导致您的应用程序立即崩溃。应处理意外的输入,而不是导致崩溃。

【讨论】:

  • 我成功将第二个json解析成字典[String:Any],最大的问题是如何设置上一个接收到的对象的属性,我可以根据属性名称进行切换设置它因此,但我认为必须有一个更明智的解决方案
  • @SorinLica 鉴于您的 cmets,我认为您在问题中忘记提及这是必不可少的,因为从外观上看,匹配应该是微不足道的,但显然并非如此。在您的评论中,您提到的属性名称不是问题的一部分,那是什么?请不要回答这个问题,而是更新您的问题。提供更多示例以及对属性是什么的清晰解释很可能会有所帮助。
  • @JoakimDanielson 匹配不是那么简单,请查看我的编辑问题,属性名称是指“启用”、“颜色”等。我只是编了一个简单的例子来描述我的问题,在实际情况下,我有大约 50 个不同的对象,每个对象都有不同的属性,所以我正在寻找一个通用的解决方案
【解决方案2】:

有多种方法可以做到这一点,但一种可能的方法可能是这样的:

struct SecAttr: Decodable {
    let id: String
    var props: Properties?

    private enum CodingKeys: String, CodingKey {
       case id
       case props
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)

        if let props = try container.decodeIfPresent(Properties.self, forKey: .props) {
          self.props = props
        } else {
          // decode Properties from the same object
          self.props = try Properties(from: decoder)
        }
    }
}

struct Properties: Decodable {
    var value: String?
    var color: String?

    mutable update(from props: Properties) {
       value = props.value ?? value
       color = color.value ?? color
    }
}

现在您可以解码原始对象,并在获得更新的属性后,只需在原始对象上更新它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-18
    • 2015-06-27
    • 2019-05-27
    • 2011-05-11
    • 1970-01-01
    • 2012-04-23
    • 2021-07-06
    • 1970-01-01
    相关资源
    最近更新 更多