有没有办法在Swift 4中的Encodable对象中插入其他键?

时间:2017-09-03 11:53:43

标签: swift4 codable

正如问题所述:我有一个符合新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)处存在除空字段之外的其他内容,但是在我的模拟中不知道只有工作站具有空闲状态,则无法知道该字段所包含的内容。所以我尝试将值"object"添加到我的工作站模型(机器人模型中的类比"workstation"),方法是将CodingKeys定义为枚举:

"robot"

这导致我的private enum CodingKeys: String, CodingKey { case object case id case state case type case position } 不再符合struct Workstation。所以我找到的唯一解决方案是添加常量Encodable,但这是一个常量,其唯一目的是添加到输出中,我想避免这种情况。

1 个答案:

答案 0 :(得分: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