【问题标题】:Struct Codable. Unable to Encode nested json结构可编码。无法编码嵌套的 json
【发布时间】:2018-09-27 10:48:38
【问题描述】:

我检查了关于 SO 提出的其他几个问题,尽管它们看起来很相似,但它们并没有解决我目前在实施中遇到的需求和挑战。到目前为止,我看到的问题和答案解决了更多可解码的问题。但是我目前遇到了 Encodable 的问题

我有嵌套的 JSON 结构,如下所示。我能够成功 decoable 并通过 json

"data": {
    "id": "XXXXXXXXXX",
    "tKey": "XXXXXXXX",
    "tID": "XXXXX",
    "type": "XXXXX",
    "hasEvent": true,
    "location": "XXXXXXXXXXXXX",
    "cover": {
        "name": "XXXXXXX",
        "parentId": "XXXXXXX",
        "parentName": "XXXXXX",
        "pop": {
            "logo": "*********",
        }
},
"men": [
  {
    "id": "XXXXXXXXXXX",
    "title": "XXXXXXX"
  },
  {
    "id": "XXXXXX",
    "title": "XXXXXX"
  },
  {
    "id": "XXXXXX",
    "title": "XXXXXX"
  }
],
"homes": [],
"homeTypes": [{
    "id": "XXXXXX",
    "subMenuId": "XXXXXXXX",
    "type": "Flat",
    "data": {
      "latitude": 29.767,
      "longitude": 0,0000,
    },
    "datas": null,
    "component": null
  },
  {
    "id": "XXXXXXXXX",
    "subMenuId": "XXXXX",
    "type": "Bubgalow",
    "data": {
      "id": "XXXXXXXXX,
      "title": "XXXXXXXXX",
      "summary": "Hello;",
  }
 }
]
}

解码器工作正常,因为我能够从服务器传递响应并填充 tableview。但是,在尝试使用可编码协议进行编码时,它似乎不起作用。请在下面找到我尝试过的代码sn-p:

Struct DataObject: Codable {
var id: String = ""
var location: String = ""
var tKey: String = ""
var tId: String = ""
var cover: cover!
var homeTypes: [Type] = [TYpe]()

var flat = Flat()
var bungalow = Bungalow()

var flat = Flat()
var bungalow = Bungalow()

enum CodingKeys: String, CodingKey {
    case id = "id"
    case type = "type"
    case location = "location"
    case tKey = "tKey"
    case tId = "tId"
    case cover = "cover"
    case homeTypes = "homeTypes"
}

enum ComponentCodingKeys: String, CodingKey {
    case id = "id"
    case type = "type"
    case component = "component"
}


required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    id = try container.decode(String.self, forKey: .id)
    if container.contains(.tKey) {
        tKey = try container.decodeIfPresent(String.self, forKey: .tKey) ?? ""
    }
    if container.contains(.tId) {
        tId = try container.decodeIfPresent(String.self, forKey: .tId) ?? ""
    }
    let typeRawValue = try container.decode(String.self, forKey: .type)
    if let tempType = SomeType(rawValue: typeRawValue) {
        type = tempType
    }
    if container.contains(.location) {
        location = try container.decodeIfPresent(String.self, forKey: .location) ?? ""
    }
    cover = try container.decode(Cover.self, forKey: .cover)
    homeTypes = try container.decode([HomeTypes].self, forKey: .component)
     for homeType in homeTypes {

          switch homeType.type {
           case .flat:
                flat = homeType.flat
          }
          case .bungalow:
                bungalow = homeType.bungalow
     }

    }

    func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(id, forKey: .id)
    try container.encode(location, forKey: .location)
    try container.encode(tKey, forKey: .tKey)
    try container.encode(tId, forKey: .tId)
    try container.encode(cover, forKey: .cover)
    //let rawValueType = try container.encode(type, forKey: .type)

    var homes = container.nestedUnkeyedContainer(forKey: .component)
    try homeTypes.forEach {
        try homes.encode($0)
     }
    }
   }
  }

【问题讨论】:

  • 实际问题是什么?您是否将编码调用包装在 do/catch 中并从控制台捕获了输出错误?
  • @Scriptable 是的,我已经做到了,当我在编码后打印时,我可以看到它实际上已编码,但是当我尝试解码时,它一直给我 nil
  • 当使用Codable 时,不鼓励为结构成员分配默认值,只需声明类型即可。如果所有键都与结构成员名称匹配,则可以省略显式 CodingKeys。而且代码无论如何都无法编译。
  • @vadian ,注意,但不会解决我目前遇到的问题。你能帮忙解决这个问题吗
  • 我建议使用多个结构而不是将 JSON 解码为单级结构。

标签: json swift codable


【解决方案1】:

您的代码存在几个问题。先把这些整理一下,然后你可能会更清楚地知道发生了什么

  • 使用let 而不是var。如果值不存在,请使用 nil 而不是空字符串。

    struct DataObject: Codable {
    
        let id: String
        let location: String?
        let tKey: String?
        let tId: String?
        let cover: Cover
        let homeTypes: [Type]
    }
    
  • 如果您的 CodingKeys 与 json 键匹配,则您无需为它们提供字符串值。所以就……

    enum CodingKeys: CodingKey {
        case id, type, location, tKey, tId, cover, homeTypes
    }
    
  • 如果您使用decodeIfPresent,则无需测试密钥是否存在

    tKey = try container.decodeIfPresent(String.self, forKey: .tKey)
    
  • 制作Type: Codable,然后

    try container.encode(homeTypes, forKey: .homeTypes)
    

【讨论】:

  • 谢谢。您能否建议在编码时如何循环遍历数组。我想我可能有什么问题
  • 仅供参考,如果键与字符串相同,则您根本不需要CodingKeys
  • 我已经让 Type 符合可编码,但我无法像解码时那样循环遍历它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-24
  • 2011-07-06
相关资源
最近更新 更多