> > > > Sure, but I don’t want to give a dictionary of unknown types: i’m very happy > to say that my dictionary is > [String : Codable] > > but > struct Foo : Codable { > let d: [String : Codable] > } > > doesn’t work; the d inside F is not itself Codable. > > That’s strange.
I don’t think it is. I would completely expect Swift to handle a dictionary of a concrete type: that’s not a heteregenous container then. When you use the protocol Codable, then it becomes heterogenous, which is the issue. > We’re actually doing exactly this and it works for us (although we are using > a concrete Codable type rather than the Codable metatype itself). > > Maybe it’s worth filing a bug on Jira > > Good luck. > > >> >> >> So basically, back to wanting to let the compiler do the work, when I make >> new structures, while still allowing for heterogenous containers. >> >> It’s also possible to give the compiler hints as to what decodes into what. >> Have you looked at the docs on the Apple foundation page? >> >> https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types >> >> <https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types> >> >> Geordie >> >> >> >> >> >> >> >> >> Begin forwarded message: >> >> >>> From: Itai Ferber <ifer...@apple.com <mailto:ifer...@apple.com>> >>> Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with >>> Codable >> >>> Date: October 19, 2017 at 10:40:28 AM PDT >> >>> To: David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> >>> Cc: Geordie Jay <geo...@gmail.com <mailto:geo...@gmail.com>>, swift-users >>> <swift-users@swift.org <mailto:swift-users@swift.org>> >>> >> >>> Why are you stuck? I think the following matches your needs, no? >>> >>> import Foundation >>> >>> enum MyType : Codable, Equatable { >>> case int(Int) >>> case string(String) >>> case list([MyType]) >>> case dictionary([String : MyType]) >>> >>> public init(from decoder: Decoder) throws { >>> // Can be made prettier, but as a simple example: >>> let container = try decoder.singleValueContainer() >>> do { >>> self = .int(try container.decode(Int.self)) >>> } catch DecodingError.typeMismatch { >>> do { >>> self = .string(try container.decode(String.self)) >>> } catch DecodingError.typeMismatch { >>> do { >>> self = .list(try container.decode([MyType].self)) >>> } catch DecodingError.typeMismatch { >>> self = .dictionary(try container.decode([String : >>> MyType].self)) >>> } >>> } >>> } >>> } >>> >>> public func encode(to encoder: Encoder) throws { >>> var container = encoder.singleValueContainer() >>> switch self { >>> case .int(let int): try container.encode(int) >>> case .string(let string): try container.encode(string) >>> case .list(let list): try container.encode(list) >>> case .dictionary(let dictionary): try container.encode(dictionary) >>> } >>> } >>> >>> static func ==(_ lhs: MyType, _ rhs: MyType) -> Bool { >>> switch (lhs, rhs) { >>> case (.int(let int1), .int(let int2)): return int1 == int2 >>> case (.string(let string1), .string(let string2)): return string1 >>> == string2 >>> case (.list(let list1), .list(let list2)): return list1 == list2 >>> case (.dictionary(let dict1), .dictionary(let dict2)): return dict1 >>> == dict2 >>> default: return false >>> } >>> } >>> } >>> >>> let values: MyType = .list([.int(42), .string("hello!"), .list([.int(9), >>> .string("hi")]), .dictionary(["zero": .int(0), "one": .int(1)])]) >>> print(values) >>> >>> let encoder = JSONEncoder() >>> let data = try encoder.encode(values) >>> print(String(data: data, encoding: .utf8)!) // => >>> [42,"hello!",[9,"hi"],{"zero":0,"one":1}] >>> >>> let decoder = JSONDecoder() >>> let decoded = try decoder.decode(MyType.self, from: data) >>> print(decoded) >>> >>> print(values == decoded) // => true >>> On 19 Oct 2017, at 20:15, David Baraff wrote: >>> >>> Begin forwarded message: >>> >>>> From: Itai Ferber <ifer...@apple.com <mailto:ifer...@apple.com>> >>>> Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with >>>> Codable >>>> Date: October 19, 2017 at 9:39:25 AM PDT >>>> To: David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> >>>> Cc: Geordie Jay <geo...@gmail.com <mailto:geo...@gmail.com>>, swift-users >>>> <swift-users@swift.org <mailto:swift-users@swift.org>> >>>> >>>> Hi David and Geordie, >>>> >>>> That approach won’t work — encoders and decoders only work directly with >>>> concrete Codable types (e.g. String, Int, MyFoo [where MyFoo is Codable], >>>> etc.). >>>> This is by design: since there is no type information stored in the JSON >>>> payload, there isn’t necessarily a way to tell how to decode the type >>>> you’re looking at, so asking for a generalCodable` isn’t helpful. >>>> >>>> Since it’s unlikely that what you truly need is a [String : Any] but >>>> really a [String : <one of String, Int, MyFoo, etc.>], one easy way to >>>> decode this type is to create a wrapper enum or similar which overrides >>>> init(from:) to be able to decode from one of those types. You can then ask >>>> to decode a [String : MyWrapperType] and use that instead. >>>> >>>> What types are you expecting in the dictionary? >>>> >>>> >>> >>> The problem is that I want to be able to encode types T where >>> (a) T is String, Int >>> (b) lists of T >>> (c ) dictionaries of type <String, T> >>> >>> The problem is the recursive nature: yes, my types are simple (say only >>> base types String and Int) but the “nesting” level may be quite deep (a >>> list of list of dictionaries of <etc.). >>> >>> >>> Let’s turn this around: in addition to the JSONEncoder, one can also use >>> the PropertyListEncoder. >>> >>> Are we saying that something one could pull from a property list file >>> (which is pretty much what i want: arbitrary deep nesting of basic types) >>> is also not Codable? So a PropertyListEncoder could not encode actual >>> property lists? >>> >>> I really do want a heterogenous container. I think I am stuck. >>> >>>> — Itai >>>> >>>> On 19 Oct 2017, at 18:11, David Baraff via swift-users wrote: >>>> >>>> I’ll try. Is that cast smart enough to apply recursively? We shall see. >>>> >>>> Sent from my iPad >>>> >>>> On Oct 19, 2017, at 7:34 AM, Geordie Jay <geo...@gmail.com >>>> <mailto:geo...@gmail.com>> wrote: >>>> >>>>> I mean can you do something along the lines of >>>>> >>>>> let codableDict = stringAnyDict as? [String : Codable] >>>>> >>>>> ? >>>>> >>>>> I’m not at a computer to test it myself >>>>> >>>>> >>>>> >>>>> >>>>> David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> >>>>> schrieb am Do. 19. Okt. 2017 um 15:45: >>>>> That’s exactly what I want. The ironic part is that I got my dictionary >>>>> by decoding a Json file. If that’s where my dictionary came from, is >>>>> there a simple way of coercing the Json serialization routines to give me >>>>> back codables, rather than Anys? >>>>> >>>>> >>>>> Sent from my iPad >>>>> >>>>> On Oct 19, 2017, at 3:38 AM, Geordie Jay <geo...@gmail.com >>>>> <mailto:geo...@gmail.com>> wrote: >>>>> >>>>>> >>>>>> David Baraff via swift-users <swift-users@swift.org >>>>>> <mailto:swift-users@swift.org>> schrieb am Do. 19. Okt. 2017 um 03:47: >>>>>> So I have simple structs like this: >>>>>> >>>>>> struct Library: Codable { >>>>>> let domain: String >>>>>> let unit: String >>>>>> } >>>>>> >>>>>> and it’s super-simple to serialize. Yay. >>>>>> >>>>>> But: >>>>>> >>>>>> struct LibraryGroup : Codable { // I wish... >>>>>> let libraries: [Library] >>>>>> let someDict: [String : Any] >>>>>> } >>>>>> >>>>>> I haven’t tried this, but is it possible to have a dictionary of [String >>>>>> : Codable] ? Because that’s exactly the type requirements you’re >>>>>> describing, no? >>>>>> >>>>>> Geordie >>>>>> >>>>>> >>>>>> So what I’m looking for is something where if the values in someDict are >>>>>> themselves Codable, I can serialize things, and if they’re not, I can’t. >>>>>> In my previous scheme, I was using NSKeyedArchiver to serialize >>>>>> everything, manualy, including someDict; in trying to switch to Codable >>>>>> I ran smack into the fact that Codable wants to know what all the types >>>>>> are, in advance. >>>>>> >>>>>> Am I just stuck? How do I get the best of both worlds, where the >>>>>> compiler can make use of the fact that it can see the data types of my >>>>>> structures, while still being able to serialize heterogenous data like >>>>>> is found in LibraryGroup? >>>>>> >>>>>> Is my only alternative to write a custom coder for LibraryGroup? Is >>>>>> there any hope I could teach Codable what to do with >>>>>> [String: Any] >>>>>> >>>>>> ? >>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> swift-users mailing list >>>>>> swift-users@swift.org <mailto:swift-users@swift.org> >>>>>> https://lists.swift.org/mailman/listinfo/swift-users >>>>>> <https://lists.swift.org/mailman/listinfo/swift-users> >>>> >>>> _______________________________________________ >>>> swift-users mailing list >>>> swift-users@swift.org <mailto:swift-users@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-users >>>> <https://lists.swift.org/mailman/listinfo/swift-users> >>>
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users