在 Swift 中合并可编码

Jan*_*Jan 5 swift codable

我有以下 Swift 结构

struct Session: Encodable {
    let sessionId: String
}
struct Person: Encodable {
    let name: String
    let age: Int
}

let person = Person(name: "Jan", age: 36)
let session = Session(sessionId: "xyz")
Run Code Online (Sandbox Code Playgroud)

我需要编码为具有以下格式的 json 对象:

{
  "name": "Jan",
  "age": 36,
  "sessionId": "xyz"
}
Run Code Online (Sandbox Code Playgroud)

的所有键Session都合并到Person

我想过使用带有自定义Encodable实现的容器结构,我使用 aSingleValueEncodingContainer但它显然只能编码一个值

struct RequestModel: Encodable {
    let session: Session
    let person: Person

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(person)
        // crash
        try container.encode(session)
    }
}

let person = Person(name: "Jan", age: 36)
let session = Session(sessionId: "xyz")
let requestModel =  RequestModel(session: session, person: person)

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

let data = try encoder.encode(requestModel)
let json = String(data: data, encoding: .utf8)!

print(json)
Run Code Online (Sandbox Code Playgroud)

我无法更改 json 格式,因为它是固定网络 API。我可以拥有 的sessionIdas 属性,Person但我想避免这种情况,因为它们是不相关的模型。

另一种方式可能是有RequestModel从复制的所有属性Session,并Person如下而是我真正的结构有更多的性能是不是很漂亮。

struct RequestModel: Encodable {
    let sessionId: String
    let name: String
    let age: Int

    init(session: Session, person: Person) {
        sessionId = session.sessionId
        name = person.name
        age = person.age
    }
}
Run Code Online (Sandbox Code Playgroud)

mar*_*uki 7

调用encode(to:)每个可编码对象,而不是singleValueContainer(). 无需定义额外的CodingKeys.

struct RequestModel: Encodable {
    let session: Session
    let person: Person

    public func encode(to encoder: Encoder) throws {
        try session.encode(to: encoder)
        try person.encode(to: encoder)
    }
}
Run Code Online (Sandbox Code Playgroud)


PGD*_*Dev 4

使用encoder.container(keyedBy: CodingKeys.self)代替singleValueContainer()并分别添加键值对,即

struct RequestModel: Encodable
{
    let session: Session
    let person: Person

    enum CodingKeys: String, CodingKey {
        case sessionId, name, age
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(person.age, forKey: RequestModel.CodingKeys.age)
        try container.encode(person.name, forKey: RequestModel.CodingKeys.name)
        try container.encode(session.sessionId, forKey: RequestModel.CodingKeys.sessionId)
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

{
  "age" : 36,
  "name" : "Jan",
  "sessionId" : "xyz"
}
Run Code Online (Sandbox Code Playgroud)

如果您仍然遇到任何问题,请告诉我。