swift - 如何实现上下文可控的 Swift Codable Encode 函数?

标签 swift codable

我正在尝试为可编码结构实现一个编码器,我可以通过传递一个上下文来控制该编码器,该上下文确定我将添加到输出 JSON 的字段。但我想不出什么好办法。

例如,假设我有以下内容:

import Foundation

struct MyStruct: Encodable {
    var a:Int = 0
    var b:Int = 0

    enum CodingKeys: String, CodingKey {
        case a
        case b
    }

    enum Context {
        case summary, full
    }

    // I can write something like this
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(a, forKey: .a)
        try container.encode(b, forKey: .b)
    }

    // ...but I want to write is something like this
    func encode(to encoder: Encoder, withContextcontext: Context ) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(a, forKey: .a)

        if context == .full
        {
            try container.encode(b, forKey: .b)
        }
    }

}

var myObject = MyStruct()
myObject.a = 10
myObject.b = 5

let jsonEncoder = JSONEncoder()
do {
    let jsonData = try jsonEncoder.encode(myObject)
    // let jsonData = try jsonEncode.encode(myObject, withContext:.full)
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print(jsonString)
} catch {
    print(error)
}

是否有任何好的解决方案可以提供与我想象的encode(:WithContext) 功能相同的效果?

我有一个我不太热衷的解决方案,即将上下文变量添加到结构中并在调用encode()之前设置它:

struct MyStruct: Encodable {
    var a:Int = 0
    var b:Int = 0
    var context = .full

    enum CodingKeys: String, CodingKey {
        case a
        case b
    }

    enum Context {
        case summary, full
    }



    // But I want to write is something like this
    func encode(to encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(a, forKey: .a)

        if context == .full
        {
            try container.encode(b, forKey: .b)
        }
    }

}

var myObject = MyStruct()
myObject.a = 10
myObject.b = 5
myObject.context = .summary

let jsonEncoder = JSONEncoder()
do {
    let jsonData = try jsonEncoder.encode(myObject)
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print(jsonString)
} catch {
    print(error)
}

不确定我想将此 Context 变量添加到我拥有的每个结构中。还有更优雅的方式吗?

最佳答案

如果您需要将一些上下文传递给Encoder,您可以随时使用Encoder.userInfo :

Any contextual information set by the user for encoding.

示例:

struct MyStruct: Encodable {
    var a:Int = 0
    var b:Int = 0

    enum CodingKeys: String, CodingKey {
        case a
        case b
    }

    enum Context {
        case summary, full

        static let encodingKey = CodingUserInfoKey(rawValue: "my_struct_context")!
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(a, forKey: .a)

        if (encoder.userInfo[Context.encodingKey] as? Context) == .full {
            try container.encode(b, forKey: .b)
        }
    }
}

var myObject = MyStruct()
myObject.a = 10
myObject.b = 5

let jsonEncoder = JSONEncoder()
jsonEncoder.userInfo = [
    MyStruct.Context.encodingKey: MyStruct.Context.summary
]

do {
    let jsonData = try jsonEncoder.encode(myObject)
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print(jsonString)
} catch {
    print(error)
}

关于swift - 如何实现上下文可控的 Swift Codable Encode 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54853890/

相关文章:

avfoundation - 从 UnsafePointer<UnsafePointer<CFloat>> 到 Swift 中的 float 组?

ios - 在 Alamofire (Swift) 中保存 cookie

ios - 从泛型类型转换为特定类型

json - 使用 Swift JSONDecoder 处理 JSON

swift - 对成员 'decode(_:forKey:)' swift4 的模糊引用

ios - 如何在 Swift 中创建嵌入式 JSON 对象并返回字符串?

ios - 如何在 Swift 中更改 UIDatePicker 的颜色?

iOS 10.3 UISegmentedControl setTitleTextAttributes 崩溃

json - Swift Codable - 如何编码和解码字符串化的 JSON 值?

json - 根据编码值 Swift 解码类