I have a class named Event that I want to make it Codable:
class Event: Codable {
let name: String
let action: String
let data: [String: Any]?
enum CodingKeys: String, CodingKey {
case name
case action
case data
}
init(name: String, action: String, data: [String: Any]?) {
self.name = name
self.action = action
self.data = data
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.name = try values.decode(String.self, forKey: .name)
self.action = try values.decode(String.self, forKey: .action)
let eventDataAsJSONString = try values.decode(String.self, forKey: .data)
if let eventDataAsData = eventDataAsJSONString.data(using: .utf8) {
self.data = try? JSONSerialization.jsonObject(with: eventDataAsData, options: []) as? [String: Any]
} else {
self.data = nil
}
}
func encode(from encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.name, forKey: .name)
try container.encode(self.action, forKey: .action)
if let data = self.data {
let eventDataAsData = try! JSONSerialization.data(withJSONObject: data, options: [])
let eventDataAsJSONString = String(data: eventDataAsData, encoding: .utf8)
try container.encode(eventDataAsJSONString, forKey: .data)
} else {
try container.encodeNil(forKey: .data)
}
}
}
but I'm getting this error:
Type 'Event' does not conform to protocol 'Encodable'
I implemented both init(from decoder: Decoder)
and encode(from encoder: Encoder)
.
so what I'm doing wrong here?
data
property with [String:Any]
type, because my users need to store some json-like information with it.Codable is Encodable , but the compiler says it does not conform to it. This may sound strange, but it's because we are using Codable as a type, and the type Codable (not the protocol definition of Codable ) does not conform to Encodable .
I know that Any is not Codable . What I need to know is how can I make it work. Related: Swift structures handling multiple tapes for a single property. In summary: you shouldn't use 'Any', but have 2 optional properties (one of type 'String' and one 'Int' in your case) and try decoding the JSON value as both.
Codable is the combined protocol of Swift's Decodable and Encodable protocols. Together they provide standard methods of decoding data for custom types and encoding data to be saved or transferred.
This is how you can use ANY in Codable
class Event<T: Codable>: Codable {
let name: String
let action: String
let data: [String: T]?
enum CodingKeys: String, CodingKey {
case name
case action
case data
}
init(name: String, action: String, data: [String: T]?) {
self.name = name
self.action = action
self.data = data
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.name = try values.decode(String.self, forKey: .name)
self.action = try values.decode(String.self, forKey: .action)
let eventDataAsJSONString = try values.decode(String.self, forKey: .data)
if let eventDataAsData = eventDataAsJSONString.data(using: .utf8) {
self.data = try? JSONSerialization.jsonObject(with: eventDataAsData, options: []) as? [String: T]
} else {
self.data = nil
}
}
func encode(from encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.name, forKey: .name)
try container.encode(self.action, forKey: .action)
if let data = self.data {
let eventDataAsData = try! JSONSerialization.data(withJSONObject: data, options: [])
let eventDataAsJSONString = String(data: eventDataAsData, encoding: .utf8)
try container.encode(eventDataAsJSONString, forKey: .data)
} else {
try container.encodeNil(forKey: .data)
}
}
}
let event = Event<String>(name: "name", action: "action", data: ["String" : "String"]) // Replace <String> with the type u want and pass that in data
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With