Reputation: 233
I want to encode Dictionary to json with JSONEncoder. It seems like a Request, receive a dictionary as parameter and encode it to json as http body. The code is looks like this:
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
But this code occurs error
Fatal error: Dictionary<String, Encodable> does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.
How could I make this encodable?
Upvotes: 6
Views: 13692
Reputation: 7341
If you want to define your struct as conforming to Codable
, you can do it like this:
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!)
It won't really work if you set params: [String: Any]
because the encoders/decoders don't know how to encode/decode Any
, but they can do it for the primitive types.
If you want more help, you should read more about the new Codable
protocol. I recommend this: https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999
Upvotes: -1
Reputation: 1403
You have to introduce type erasure as follows:
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))
Upvotes: 3