I have a JSON array of objects. Simplified, it has this form:
[
{"name": "Tinky Winky"},
{"name": "Dipsy"},
{"name": "Laa-Laa"},
{"name": "Po"}
]
I can create a struct Tubby
can can decode an individual instance from the array:
struct Tubby: Codable {
let name: String
}
I'd like to create a struct Tubbies
that can decode from the array of JSON:
struct Tubbies: Codable {
let tubbies: [Tubby]
init(from decoder: Decoder) throws {
// What goes here?
tubbies = ???
}
… but now I'm stuck with how I should decode? I'd like to just do:
init(from decoder: Decoder) throws {
// What goes here?
tubbies = decoder.decode([Tubby].self)
}
But Decoder
doesn't offer a decode
. It has:
/// Returns the data stored in this decoder as represented in a container
/// keyed by the given key type.
///
/// - parameter type: The key type to use for the container.
/// - returns: A keyed decoding container view into this decoder.
/// - throws: `DecodingError.typeMismatch` if the encountered stored value is
/// not a keyed container.
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey
/// Returns the data stored in this decoder as represented in a container
/// appropriate for holding values with no keys.
///
/// - returns: An unkeyed container view into this decoder.
/// - throws: `DecodingError.typeMismatch` if the encountered stored value is
/// not an unkeyed container.
func unkeyedContainer() throws -> UnkeyedDecodingContainer
/// Returns the data stored in this decoder as represented in a container
/// appropriate for holding a single primitive value.
///
/// - returns: A single value container view into this decoder.
/// - throws: `DecodingError.typeMismatch` if the encountered stored value is
/// not a single value container.
func singleValueContainer() throws -> SingleValueDecodingContainer
Both (this was a mistake, as the answers clarify – thanks!) and singleValueContainer
unkeyedContainer
throw for the array with a message suggesting that they don't support an array. Can I use container(keyedBy:)
, and what should I pass as the key?
I don't think it was a good approach, since [Tubby].self
is simple enough to use anywhere.
But if you just want to wrap the array inside another type, you should have something like this:
struct Tubbies: Codable {
let tubbies: [Tubby]
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.tubbies = try container.decode([Tubby].self)
}
}
struct Tubbies: Codable {
let tubbies: [Tubby]
init(from decoder: Decoder) throws {
tubbies = try [Tubby](from: decoder)
}
}
let tubbies: Tubbies = try! JSONDecoder().decode(Tubbies.self, from: jsonData)