Reputation: 1974
I want to send empty Dictionary like this
“visitor_attrs”: {}
I try to implement empty dictionary in a class. In the decoder I get the warning:
No 'decode' candidates produce the expected contextual result type 'Dictionary'
How can I do this?
var data: String
var event: String
var visitorAttrs: Dictionary<String, Any>
init(data: String, event: String) {
self.data = data
self.event = event
self.visitorAttrs = [:]
}
private enum CodingKeys: String, CodingKey {
case data
case event
case visitorAttrs = "visitor_attrs"
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.data = try container.decode(String.self, forKey: .data)
self.event = try container.decode(String.self, forKey: .event)
self.visitorAttrs = try container.decode(Dictionary<String:Any>.self, forKey: .visitorAttrs)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.data, forKey: .data)
try container.encode(self.event, forKey: .event)
try container.encode(self.visitorAttrs, forKey: .visitorAttrs)
}
Upvotes: 0
Views: 1326
Reputation: 51945
The error is caused by having Any as value in your dictionary and Any isn't decodable, replace it with String (or whatever data type you have) and this should work.
var visitorAttrs: Dictionary<String, String>
Fix this issue and you will get the expected behaviour
let item = Item(data: "data", event: "event") //I gave your class the name Item
let encoder = JSONEncoder()
do {
let data = try encoder.encode(item)
if let str = String(data: data, encoding: .utf8) {
print(str)
}
} catch {
print(error)
}
Output is
{"event":"event","visitor_attrs":{},"data":"data"}
Upvotes: 2
Reputation: 183
My assumption is that because the visitorAttrs is empty on your JSON response it fails to get a dictionary out of it as there is none.
You have two options (as far as I know)
Make the visitorAttrs property optional, that way if you don't have anything it will still be able to decode properly, or,
Set the value of visitorAttrs to an empty dictionary if it fails to decode it
let visitorAttrs = try? container.decode(Dictionary<String:Any>.self, forKey: .visitorAttrs)
self.visitorAttrs = visitorAttrs ?? [:]
Upvotes: 2