我正在使用一种协议来编码一致的结构:
protocol RequestParameters: Encodable {
}
extension RequestParameters {
func dataEncoding() -> Data? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
return data
}
}
这对于编码此类结构非常有用:
struct StoreRequest: RequestParameters {
var storeCode : String
var storeNumber : String
}
但是,有时我的请求需要一些“共享”参数:
struct SpecialStoreRequest: RequestParameters {
var storeCode : String
var storeNumber : String
// Shared Parameters that appear in 70% of my requests
var sharedParam1 : String?
var sharedParam2 : String?
var sharedParam3 : String?
var sharedParam4 : String?
var sharedParam5 : String?
}
我可以在需要它们的每个请求结构中简单地编写这些共享参数,但是我想知道是否可以将它们共享到另一个结构中,并以某种方式修改编码以在顶层进行编码?
我在想类似的东西:
struct SharedParameters {
// Shared Parameters that appear in 70% of my requests
var sharedParam1: String?
var sharedParam2: String?
var sharedParam3: String?
var sharedParam4: String?
var sharedParam5: String?
enum CodingKeys: String, CodingKey {
case sharedParam1
case sharedParam2
case sharedParam3
case sharedParam4
case sharedParam5
}
}
struct SpecialStoreRequest: RequestParameters {
var storeCode : String
var storeNumber : String
var sharedParams : SharedParameters?
}
最后一个结构的问题是,生成的编码与第一个编码不相同,因为我的共享参数将被编码为 INSIDE “ sharedParams”键:
{
"storeCode" : "ABC",
"storeNumber" : "123456",
"sharedParams" : {"sharedParam1" : "A","sharedParam2" : "B", ...}
}
但是我需要将它们与其他现有参数(在这种情况下为storeCode和storeNumber)一起编码。
{
"storeCode" : "ABC",
"storeNumber" : "123456",
"sharedParam1" : "A",
"sharedParam2" : "B",
...
}
编辑: 为了使问题更清楚,假设有可能,如何使此结构直接在其父级上通过键值编码?
extension SharedParameters: Encodable {
func encode(to encoder: Encoder) throws {
// What goes here? (Is it even possible?)
}
}
答案 0 :(得分:0)
想知道是否可以将它们分组为另一种结构,并以某种方式修改编码以将其编码为顶层?
您不能更改当前的Encoder
及其行为,但是
您可以通过自定义 Encode
函数
制作两个容器并使用共享参数CodingKeys
进行编码
sharedParameters
变量中的个参数。
观察下面的代码。
struct Others: Codable {
var sharedParam1: String
var sharedParam2: String
enum CodingKeys: String, CodingKey {
case sharedParam1
case sharedParam2
}
}
struct MyCustomReq: Codable {
var p1: String
var p2: String
var shared: Others
enum CodingKeys: String, CodingKey {
case p1
case p2
case shared
}
}
extension MyCustomReq {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(p1, forKey: .p1)
try container.encode(p2, forKey: .p2)
//Others = sharedParams container. with its CodingKeys
var container2 = encoder.container(keyedBy: Others.CodingKeys.self)
try container2.encode(shared.sharedParam1, forKey: .sharedParam1 )
try container2.encode(shared.sharedParam1, forKey: .sharedParam2)
}
}
使用测试
var oth = Others(sharedParam1: "Shared1", sharedParam2: "Shared2")
var object = MyCustomReq.init(p1: "P1", p2: "P2", shared: oth)
let encoder = JSONEncoder()
let data = try encoder.encode(object)
print(String(data: data, encoding: .utf8)!)
输出
{ “ p2”:“ P2”,
“ sharedParam1”:“ Shared1”,
“ p1”:“ P1”,
“ sharedParam2”:“ Shared1”
}
现在让我们进入下一步
创建一个类并在其中自定义共享的Encoder
,然后调用其函数。
观察最终结果。
final class MyParamsEncoded: Codable {
var sharedParams: Others
init (sharedParam: Others) {
self.sharedParams = sharedParam
}
func encode(to encoder: Encoder) throws {
var container2 = encoder.container(keyedBy: Others.CodingKeys.self)
try container2.encode(sharedParams.sharedParam1, forKey: .sharedParam1 )
try container2.encode(sharedParams.sharedParam1, forKey: .sharedParam2)
}
}
现在,添加此类后,您可以像这样使用它, 而且它将给您相同的结果。
extension MyCustomReq {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(p1, forKey: .p1)
try container.encode(p2, forKey: .p2)
//Using the class wrapping, final Result of using
var cont = try MyParamsEncoded(sharedParam: shared).encode(to: encoder)
}
}