【问题标题】:Is there a way to insert additional keys in an Encodable Object in Swift 4?有没有办法在 Swift 4 的可编码对象中插入额外的键?
【发布时间】:2017-09-03 11:53:43
【问题描述】:

正如问题所述:我有一个符合新的Encodable 协议的结构,并希望在结构本身中插入不作为变量或常量存在的键和值。我当前的解决方法是将它们作为常量添加到结构中,其唯一目的是添加到生成的 JSON 输出中。 func encode(to encoder: Encoder) throws { ... }有没有办法做到这一点?


背景资料

我有一个相当大的 Swift 4 项目,它需要一个 JSON 输出来在项目本身之外生成统计信息和可视化,所以我几乎所有的结构、类和枚举都符合新的 Encodable 协议。输出已经在工作,但在某些方面可读性很差。特别是在一个描述光栅化工厂布局中的字段的结构中:

该字段有一个位置(坐标为x: Inty: Int)和自定义enum FieldType 的内容,包含以下情况:

case wall
case entrance(robots: Set<Robot>)
case exit(robots: Set<Robot>)
case workstation(object: Workstation)
case robot(object: Robot)
case empty

PositionFieldTypeRobotWorkstationField 本身已经实现了Encodable,但问题是我的字段的 JSON 输出如下所示:

...
{
    "content" : "empty",
    "position" : {
        "x" : 9,
        "y" : 6
    }
},
{
    "content" : "empty",
    "position" : {
        "x" : 10,
        "y" : 6
    }
},
{
    "content" : {
        "id" : 3,
        "state" : "idle",
        "type" : "C",
        "position" : {
            "x" : 11,
            "y" : 6
        }
    },
    "position" : {
        "x" : 11,
        "y" : 6
    }
},
{
    "content" : "empty",
    "position" : {
        "x" : 12,
        "y" : 6
    }
},
...

正如您所见,除了位置 (11, 6) 处的空白字段外,还有其他内容,但不知道在我的模拟中只有工作站处于空闲状态,因此无法知道该字段包含什么内容。因此,我尝试通过将 CodingKeys 定义为枚举,将值为 "workstation" 的键 "object" 添加到我的工作站模型(机器人模型中的类比 "robot"):

private enum CodingKeys: String, CodingKey {
    case object
    case id
    case state
    case type
    case position
}

这导致我的struct Workstation 不再符合Encodable。所以我找到的唯一解决方案是添加一个常量let object = "workstation",但这是一个常量,其唯一目的是添加到输出中,我想避免这种情况。

【问题讨论】:

  • 您能否提供一个如何对entranceexit 字段类型进行编码的示例。它们都有 Set&lt;Robot&gt; 作为关联值
  • @CodeDifferent This is the output 的入口场有 4 个机器人和两个围墙场进行比较。出口看起来完全一样,所以如果不知道入口总是在墙壁的第一行而出口在最后一行,就无法知道哪个是哪个。这也可以通过在编码过程中添加键值对的某种方式来解决。

标签: swift4 codable


【解决方案1】:

您必须为FieldType 编写一个自定义编码器:

enum FieldType: Encodable {
    case wall
    case entrance(robots: Set<Robot>)
    case exit(robots: Set<Robot>)
    case workstation(object: Workstation)
    case robot(object: Robot)
    case empty

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()

        switch self {
        case .wall:
            try container.encode("wall")
        case .entrance(let robotset):
            try container.encode(robotset)
        case .exit(let robotSet):
            try container.encode(robotSet)
        case .workstation(let workstation):
            try container.encode(workstation)
        case .robot(let robot):
            try container.encode(robot)
        case .empty:
            try container.encode("empty")
        }
    }
}

(假设RobotWorkstation 已经是Encodable

【讨论】:

  • 这就是我已经为获得上述 JSON 输出所做的工作。我要问的是,是否有可能将行 "object" : "workstation" 添加到编码的工作站,而无需在工作站的代码中添加像 let object = "workstation" 这样的常量。或者一般来说:是否可以对 Swift 类、Struct、Enum 等的变量和常量进行编码……
猜你喜欢
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 2018-08-15
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 2017-02-03
相关资源
最近更新 更多