Thank you Brent for your effort. I will try this way. By the way I thought that the protocol conformance with conditions were already retained/adopted in Swift 4. You seem to say that it was postponed. It’s too bad in my opinion. But thanks again for the info.
> On 18 Oct 2017, at 23:38, Brent Royal-Gordon <br...@architechies.com> wrote: > >> On Oct 17, 2017, at 10:00 AM, Thierry Passeron via swift-users >> <swift-users@swift.org> wrote: >> >> Hi everyone, >> >> In the process of familiarising myself with Encodable/Decodable protocols I >> was trying to apply it to the Range struct in order to persist a Range in >> CoreData records. However, I seem to hit the wall with it and keep getting >> errors. This happens in the Xcode 9.0.1 playground, not sure which swift >> version is used if it’s 4 or 3.x but anyways, I get “Ambiguous reference to >> member ‘encode(_:forKey:)’ on every encode/decode method calls. >> >> extension Range { >> enum CodingKeys : String, CodingKey { >> case upperBound >> case lowerBound >> } >> } >> >> extension Range: Codable { >> >> public func encode(to encoder: Encoder) throws { >> var container = encoder.container(keyedBy: CodingKeys.self) >> try container.encode(upperBound, forKey: .upperBound) >> try container.encode(lowerBound, forKey: .lowerBound) >> } >> >> public init(from decoder: Decoder) throws { >> let values = try decoder.container(keyedBy: CodingKeys.self) >> self.upperBound = try values.decode(Bound.self, forKey: .upperBound) >> self.lowerBound = try values.decode(Bound.self, forKey: .lowerBound) >> } >> >> } >> >> How would one add Codable support to such a struct? I’m feeling it may >> require a bit of “where” clauses in extension because of the Generic aspect >> of this struct but I fail to make the compiler happy. > > What you'd *like* to be able to do is say that a Range is codable only when > its bounds are also codable: > > extension Range: Codable where Bound: Codable { > … > } > > But this isn't currently supported in Swift. (The compiler team is working on > it right now, and it'll probably be here in Swift 5, if not in 4.1.) So for > the time being, you have to fake it dynamically. Unless you want to use > private APIs, the easiest way is probably to use a dictionary: > > extension Range: Decodable /* where Bound: Decodable */ { > public init(from decoder: Decoder) throws { > let dict = try [String: Bound](from: decoder) > > guard let lower = > dict[CodingKey.lowerBound.stringValue] else { > throw DecodingError.valueNotFound(Bound.self, > .init(codingPath: decoder.codingPath + [CodingKey.lowerBound], > debugDescription: "lowerBound not found") > } > guard let lower = > dict[CodingKey.upperBound.stringValue] else { > throw DecodingError.valueNotFound(Bound.self, > .init(codingPath: decoder.codingPath + [CodingKey.upperBound], > debugDescription: "upperBound not found") > } > > self.init(uncheckedBounds: (lower: lower, upper: upper)) > } > } > > extension Range: Encodable /* where Bound: Encodable */ { > public func encode(to encoder: Encoder) throws { > try [CodingKey.lowerBound.stringValue: lowerBound, > CodingKey.upperBound.stringValue: upperBound].encode(to: encoder) > } > } > > This should mimic the structure you'll eventually be able to generate with a > keyed container; when Swift becomes able to do this properly, you can update > the code to encode and decode directly. > > Hope this helps, > -- > Brent Royal-Gordon > Architechies
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users