我有以下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")
字符串
我需要将其编码为具有以下格式的json对象:
{
"name": "Jan",
"age": 36,
"sessionId": "xyz"
}
型
其中Session
的所有键合并到Person
的键中
我考虑过将容器结构体与自定义的Encodable
实现一起使用,其中我使用SingleValueEncodingContainer
,但它显然只能编码一个值
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)
型
我不能改变json格式,因为它是一个固定的网络API。我可以将sessionId
作为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
}
}
型
4条答案
按热度按时间b4lqfgs41#
调用每个可编码对象的
encode(to:)
,而不是singleValueContainer()
。它可以将多个可编码对象连接到一个可编码对象中,而无需定义额外的CodingKeys
。字符串
tv6aics12#
使用
encoder.container(keyedBy: CodingKeys.self)
而不是singleValueContainer()
,并分别添加键值对,即字符串
输出:
型
让我知道如果你仍然面临任何问题。
jexiocij3#
我想在这里扩展@marty-suzuki的答案,因为如果你不小心的话,可能会错过一些细微的差别。下面是我的代码版本:
字符串
简单地用一个可编码对象的数组示例化,并将结果对象本身视为可编码对象。现在,使用此方法时需要记住几个重要注意事项:
1.在JSON中只能有一种类型的根对象,它可以是单个值、数组或字典。因此,当你在各种可编码对象中实现
encode(to:)
时,千万不要使用encoder.singleValueContainer
创建容器。1.你希望合并的每个对象都必须在同一种容器上操作,所以如果其中一个使用
unkeyedContainer()
,那么它们都必须使用。类似地,如果一个使用container(keyedBy:)
,那么其他的也必须使用。1.如果你使用的是键控容器,那么所有组合对象中的两个变量不能共享相同的键名!否则,你会发现它们会互相覆盖,因为它们被解析到同一个字典中。
另一种可以缓解这些问题,但不会产生相同的JSON结构的方法是:
型
现在,这有点不方便,因为我们不能简单地提供一个符合Encodable的对象数组;它需要确切地知道它们被称为
container.encode()
。结果是一个JSON对象,其根对象是数组,每个子元素表示为该数组中的一个元素。事实上,你可以进一步简化它,就像这样:型
...这当然会导致一个字典根对象,其编码形式为
MyEncodableA
,键为elementA
,MyEncodableB
为elementB
。这完全取决于你想要什么样的结构。
u0njafvf4#
我个人觉得我的版本最方便
字符串
使用情况
型
测试结果
[“平台”:“ios”,“transation”:[“1”,“2”],“deviceId”:“deviceId”]