You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SR-9965 Decodable: type mismatch error when decoding string to date as dictionary key
Issue Description:
Consider the following attempt to deserialise JSON:
importUIKitletjson = """ { "localisedTexts": { "454198ea-bee1-49ac-a8b9-1ceaf8220a85": { "EN-US": "What is your name?", "EN-UK": "What is your name?" } } } """.data(using: .utf8)!
structMyStruct: Codable {
letlocalisedTexts: Dictionary<UUID, Dictionary<String, String>>
}
letjsonDecoder = JSONDecoder()
do {
letx = tryjsonDecoder.decode(MyStruct.self, from: json)
print(x)
} catchleterr {
print(err)
}
I would expect my object to get deserialised from the json. Instead, I get this error message: typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "localisedTexts", intValue: nil)], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
Here's some other things I've tried:
Changing `let localisedTexts: Dictionary<UUID, Dictionary<String, String>>` to `let localisedTexts: Dictionary<String, Dictionary<String, String>>` deserialises my object just fine.
Changing `UUID` to `Int` for the key (and changing the JSON correspondingly) works too.
I've attached a playground file for illustrative purpose.
The text was updated successfully, but these errors were encountered:
I see your point but I tried decoding a UUID when it lies in the 'value' part of a key-value pair and that works fine. This seems like inconsistent behaviour to me?
Either way, the error message displayed by the decoder isn't indicative of the problem.
To give a bit more detail — the implementation for Dictionary's Codable conformance has a choice to make: it can either encode its keys and values into a KeyedEncodingContainer or an UnkeyedEncodingContainer. If it uses a KeyedEncodingContainer, the only way it can do so is if it is able to convert its keys into {{CodingKey}}s, and that's only really possible if the key type is already either String or Int. Dictionary can't know ahead of time how UUID would choose to encode itself (or be encoded), nor can it easily ask to "just encode" UUID and check for its representation after the fact.
This means that even for types like UUID, which would encode as a String, the only thing Dictionary can do is fall back to UnkeyedEncodingContainer. Decoding matches this structure — since Dictionary can't get a KeyedDecodingContainer keyed by {{UUID}}s, there's no way it could convert those strings to {{UUID}}s.
I agree that the error message is not terribly helpful, and we can likely do a better job there.
Attachment: Download
Environment
I ran the code in a Playground file and in an iOS app as well.
Xcode Version: 10.0 (10A255)
macOS Version: 10.14 (18A391)
Swift Version: 4.2
Additional Detail from JIRA
md5: 6739ca72461dc717465a4d9b646ad032
is duplicated by:
Issue Description:
Consider the following attempt to deserialise JSON:
I would expect my object to get deserialised from the json. Instead, I get this error message:
typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "localisedTexts", intValue: nil)], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
Here's some other things I've tried:
Changing `let localisedTexts: Dictionary<UUID, Dictionary<String, String>>` to `let localisedTexts: Dictionary<String, Dictionary<String, String>>` deserialises my object just fine.
Changing `UUID` to `Int` for the key (and changing the JSON correspondingly) works too.
I've attached a playground file for illustrative purpose.
The text was updated successfully, but these errors were encountered: