【问题标题】:How to manually implement Codable for multiple structs according to 'type'?如何根据“类型”手动实现多个结构的 Codable?
【发布时间】:2018-09-14 20:26:02
【问题描述】:

考虑以下 json:

{
    "from": "Guille",
    "text": "Look what I just found!",
    "attachments": [
        {
            "type": "image",
            "payload": {
                "url": "http://via.placeholder.com/640x480",
                "width": 640,
                "height": 480
            }
        },
        {
            "type": "audio",
            "payload": {
                "title": "Never Gonna Give You Up",
                "url": "https://audio.com/NeverGonnaGiveYouUp.mp3",
                "shouldAutoplay": true,
            }
        }
    ]
}

还有以下 Swift 结构:

struct ImageAttachment: Codable {
    let url: URL
    let width: Int
    let height: Int
}
struct AudioAttachment: Codable {
    let title: String
    let url: URL
    let shouldAutoplay: Bool
}

enum Attachment {
  case image(ImageAttachment)
  case audio(AudioAttachment)
  case unsupported
}

extension Attachment: Codable {
  private enum CodingKeys: String, CodingKey {
    case type
    case payload
  }
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let type = try container.decode(String.self, forKey: .type)
    switch type {
    case "image":
      let payload = try container.decode(ImageAttachment.self, forKey: .payload)
      self = .image(payload)
    case "audio":
      let payload = try container.decode(AudioAttachment.self, forKey: .payload)
      self = .audio(payload)
    default:
      self = .unsupported
    }
  }
  ...
}

如果“有效负载”关键参数是平坦的(也就是没有“有效负载”),我将如何处理类似的用例:

{
  "type": "image",
  "url": "http://via.placeholder.com/640x480",
  "width": 640,
  "height": 480
}

{
  "type": "audio",
  "title": "Never Gonna Give You Up",
  "url": "https://audio.com/NeverGonnaGiveYouUp.mp3",
  "shouldAutoplay": true,
 }

我无法弄清楚如何为平面案例正确实现 init 解码器,因为同时保留了附件结构并允许未来的灵活性(添加更多类型的附件)。

【问题讨论】:

  • 与复制基本相同;你必须实时读取密钥,看看你得到了什么。
  • 我不确定它是否重复。这里的键定义明确,只是“类型”定义了哪些键将实际存在(并且已经在结构中定义)。副本也有一个嵌套结构,就像“有效负载”一样,它没有回答如何在同一级别的初始化解码中解析它的问题。

标签: json swift codable


【解决方案1】:

你只需要做一点小改动

extension Attachment: Codable {
    private enum CodingKeys: String, CodingKey {
        case type
        case payload
    }

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

        // The attachment data is nested if it has the `payload` key
        let isNested = container.allKeys.contains(.payload)

        switch type {
        case "image":
            // If the attachment data is nested inside the `payload` property, decode
            // it from that property. Otherwise, decode it from the current decoder
            let payload = try isNested ? container.decode(ImageAttachment.self, forKey: .payload) : ImageAttachment(from: decoder)
            self = .image(payload)
        case "audio":
            // Same as image attachment above
            let payload = try isNested ? container.decode(AudioAttachment.self, forKey: .payload) : AudioAttachment(from: decoder)
            self = .audio(payload)
        default:
            self = .unsupported
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多