2

I just tried this:

let test = "{ \"de\": \"Bisasam\", \"en\": \"Bulbasaur\" }"
let data = test.data(using: .utf8)!
do {
    let result = try JSONDecoder().decode([String: String].self, from: data)
    print("") // breakpoint here works
} catch {
    print("")
}

This works fine, however when I try to do this instead:

enum Lg: String, CaseIterable, Decodable {
    case deutsch = "de"
    case english = "en"
}

let test = "{ \"de\": \"Bisasam\", \"en\": \"Bulbasaur\" }"
let data = test.data(using: .utf8)!
do {
    let result = try JSONDecoder().decode([Lg: String].self, from: data)
    print("")
} catch {
    print("") // breakpoint here
}

With this error:

▿ DecodingError ▿ typeMismatch : 2 elements

  • .0 : Swift.Array ▿ .1 : Context
    • codingPath : 0 elements
    • debugDescription : "Expected to decode Array but found a dictionary instead."
    • underlyingError : nil

What am I doing wrong?

Thanks for your help

2

1 Answer 1

3

When you use a non-String non-Int type as the dictionary key, Dictionary's Decodable implementation expects an array of key value pairs, i.e.:

["de", "foo", "en", "bar"]

This decodes to [.deutsch: "foo", .english: "bar"].

JSON keys can only be strings after all, and the Decodable implementation doesn't know how to convert a random Decodable value into a string. It could have been made to check for RawRepresentable with RawValue == String, but it wasn't.

One thing that it does check for though, is CodingKeyRepresentable, if you just conform Lg to that, then you can decode a JSON dictionary correctly.

Conforming a type to CodingKeyRepresentable lets you opt in to encoding and decoding Dictionary values keyed by the conforming type to and from a keyed container, rather than encoding and decoding the dictionary as an unkeyed container of alternating key-value pairs.

extension Lg: CodingKeyRepresentable, CodingKey {
    init?<T>(codingKey: T) where T : CodingKey {
        self.init(rawValue: codingKey.stringValue)
    }
    
    var codingKey: CodingKey {
        self
    }
}

Note that I also conformed it to CodingKey to make it easier to write the codingKey property required by CodingKeyRepresentable.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.