Swift Codable:是否可以将结构从自身内部编码一级;编码(至:)”;功能?

Swift Codable:是否可以将结构从自身内部编码一级;编码(至:)”;功能?,swift,codable,encodable,Swift,Codable,Encodable,我正在使用协议对一致性结构进行编码: protocol RequestParameters: Encodable { } extension RequestParameters { func dataEncoding() -> Data? { guard let data = try? JSONEncoder().encode(self) else { return nil } return data } } struct Store

我正在使用协议对一致性结构进行编码:

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    
}
这对于编码此类结构非常有效:

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?
}
最后一个结构的问题是,生成的编码与第一个结构不同,因为我的共享参数将在“sharedParams”键中进行编码:

但我需要的是将它们与我的其他现有参数(本例中的storeCode和storeNumber)一起编码


编辑: 为了让问题更清楚,假设可能的话,这里应该怎么做才能让这个结构直接在其父结构上通过键值进行编码

extension SharedParameters: Encodable {

    func encode(to encoder: Encoder) throws {

        // What goes here? (Is it even possible?)

    }
}
我想知道是否有可能将它们分组到另一个结构中,并以某种方式修改编码以在顶层编码它们

您无法更改当前的
编码器及其行为方式,但是

您可以通过自定义
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”

}

现在让我们进入下一步

创建一个类,定制共享代码的
编码器
,然后调用它的函数

观察最终结果

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)

}
}

那些参数总是有相同的值吗?@RajmundZawiślak我不是必须手动编码每个请求吗?因为这些参数在请求类型之间共享,但是每个类型都有自己的属性。如果是这样的话,我就更容易像第一种情况那样显式地编写它们。如果您的意思是,让“SharedParameters”编码行为执行此操作,这就是我的问题,因为我找不到如何将其添加到上面的容器(而不是下面的容器)。@Tobi否,参数键是相同的,但值可能会根据请求而更改。(在某些情况下,它们甚至可能根本不需要,这就是我将它们设置为可选项的原因)。。。。为什么不使用协议?很抱歉回复太晚。这个答案的问题是,我仍然必须为每个“MyCustomReq”请求创建扩展,因为每个请求的特定参数都在那里定义。我很抱歉没有说得更清楚。我开始相信这在结构中是不可能的,因为我可能需要使用类函数“public mutating func superEncoder(forKey:Self.key)->Encoder”。你需要创建扩展并尝试使用我给你的最后一个类函数,我认为这是唯一可能的方法。在这种情况下,你不能更改解码器的工作,但是你可以完全从头开始创建一个新的来处理你的案件,我认为这需要更多的时间,这是最方便的事情imo@Pochi我已经搜索了很多东西,并尝试了很多东西来找到这个答案,所以我很确定这是最方便的方法。德国劳埃德船级社,如果你得到了什么,请告诉我,因为我期待着了解,如果有