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

时间:2019-02-24 16:17:04

标签: swift codable

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

例如说我有以下内容:

mysql> create table Members(
    -> M_id int not null,
    -> B_id int not null,
    -> M_name varchar(20),
    -> M_address varchar(20),
    -> Issue DATE,
    -> Return DATE,
    -> Expiry_date DATE,
    -> primary key(M_id),
    -> foreign key(B_id) references books(B_id));

有没有什么好的解决方案可以提供与我想象中的encode(:WithContext)功能相同的效果?

我有一个我不太热衷的解决方案是将上下文变量添加到struct并在调用encode()之前对其进行设置:

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)
}

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

1 个答案:

答案 0 :(得分:2)

如果您需要将上下文传递给Encoder,则可以始终使用Encoder.userInfo

  

用户为编码设置的任何上下文信息。

示例:

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)
}