I'm having trouble getting my Codable type to properly decode. I have read a few tutorials on making Codable
enums with associated types. I've searched for typos, name mismatches, or whatever but I can't spot anything wrong with this. And yet whenever I try to decode on of these structs (a Layer.. this defines an "Attribute" on a layer in an extension.. but all the other predefined parts of Layer are being properly en/de-coded), I hit a "key not found" exception in the decode(from decoder:)
method.
extension Layer {
struct Attribute: Codable {
enum Value: Codable {
case pulse(Double)
case flash(Double)
case draw(Double)
private enum CodingKeys: String, CodingKey {
case pulse, flash, draw
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .pulse(let value):
try container.encode(value, forKey: .pulse)
case .flash(let value):
try container.encode(value, forKey: .flash)
case .draw(let value):
try container.encode(value, forKey: .draw)
}
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
do {
let value = try values.decode(Double.self, forKey: .pulse)
self = .pulse(value)
} catch (let error) {
print(error)
}
do {
let value = try values.decode(Double.self, forKey: .draw)
self = .draw(value)
} catch (let error) {
print(error)
}
do {
let value = try values.decode(Double.self, forKey: .flash)
self = .flash(value)
} catch (let error) {
print(error)
}
self = .draw(0.0)
}
}
var value: Value
init(value: Value) {
self.value = value
}
}
}
We can make enum with raw values conform to the Codable protocol by just adopting it. 1 We can make enum with raw value support Codable by just adopting it. By declaring protocol conformance, Role becomes a codable type. 2 We can use it in a codable context without doing any extra work.
Codable; the data-parsing dream come true!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.
The simplest way to make a type codable is to declare its properties using types that are already Codable . These types include standard library types like String , Int , and Double ; and Foundation types like Date , Data , and URL .
Swift makes it is effortless to decode Enums from its raw value. All you need to do are make sure your enum is raw representable enum, e.g., can be represented by Int or String , and that your enum conforms to Codable protocol. Here is a struct and enum ready for encoding/decoding.
I think you should first check whether a key exists in the decoder's container or not, before decoding it. Currently, you are doing this:
do {
let value = try values.decode(Double.self, forKey: .pulse)
self = .pulse(value)
} catch (let error) {
print(error)
}
do {
let value = try values.decode(Double.self, forKey: .draw)
self = .draw(value)
} catch (let error) {
print(error)
}
do {
let value = try values.decode(Double.self, forKey: .flash)
self = .flash(value)
} catch (let error) {
print(error)
}
There is no way that the decoder container is going to have all three keys in there, isn't it?
So, check before decoding:
if values.contains(.pulse) {
do {
let value = try values.decode(Double.self, forKey: .pulse)
self = .pulse(value)
return // remember to return here, so you don't set self back to .draw(0.0) again!
} catch (let error) {
print(error)
}
} else if values.contains(.draw) {
do {
let value = try values.decode(Double.self, forKey: .draw)
self = .draw(value)
return
} catch (let error) {
print(error)
}
} else if values.contains(.flash) {
do {
let value = try values.decode(Double.self, forKey: .flash)
self = .flash(value)
return
} catch (let error) {
print(error)
}
}
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