如何在 Swift 4 中使用 JSONEncoder 编码字典



我想用JSONEncoder将Dictionary编码为json。它看起来像一个请求,接收字典作为参数并将其编码为 json 作为 http 正文。代码如下所示:

let dict = ["name": "abcde"]
protocol Request {
    var params: [String: Encodable] { get set }
    func encode<T>(_ value: T) throws -> Data where T : Encodable
}
extension Request {
    func encode<T>(_ value: T) throws -> Data where T : Encodable {
        return try JSONEncoder().encode(value)
    }
    var body: Data? {
        if let encoded = try? self.encode(self.params) {
            return encoded
        }
        return nil
    }
}
struct BaseRequest: Request {
    var params: [String : Encodable]
}
let req = BaseRequest(params: dict)
let body = req.body

但是此代码发生错误

致命错误:字典<字符串,可编码>不符合可编码,因为可编码不符合自身。必须使用具体类型进行编码或解码。

我怎样才能使它可编码?

您必须引入类型擦除,如下所示:

struct AnyEncodable: Encodable {
    let value: Encodable
    init(value: Encodable) {
        self.value = value
    }
    func encode(to encoder: Encoder) throws {
        try value.encode(to: encoder)
    }
}
struct Model: Encodable {
    var params: [String: AnyEncodable]
}
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let json = try! encoder.encode(
    Model(
        params: [
            "hello" : AnyEncodable.init(value: "world")
        ]
    ).params
)
print(String(data: json, encoding: .utf8))

如果你想将你的结构定义为符合Codable,你可以这样做:

struct Model: Codable {
    var param1: String
    var param2: Int
}
let model = Model(param1: "test", param2: 0)
let encoded = try? JSONEncoder().encode(model)
let decoded = try? JSONDecoder().decode(Model.self, from: encoded!)

如果您设置params: [String: Any],它将无法真正工作,因为编码器/解码器不知道如何编码/解码Any,但它们可以为基元类型执行此操作。

如果您需要更多帮助,您应该阅读有关新Codable协议的更多信息。我推荐这个:https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999

最新更新