0
votes

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

2 Answers

2
votes

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

1
votes

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)

  1. Make the visitorAttrs property optional, that way if you don't have anything it will still be able to decode properly, or,

  2. 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 ?? [:]