NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

What is decoder.container?

Forums > 100 Days of SwiftUI

im on day 49 and when i was reading the second article i saw decoder.container which i didnt understand. Heres the full code

required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)

also i saw it on encoder aswell but i presume its the same as decoder, so ill understand once someone explains me the regular one. Also i seem to be a bit lost on the whole Codable/ data saving learning part. I grasp everything else very well but that. is there any article i could read. that would re-teach me. the same(or similar) things? or should i just re read the regular hws articles?


A container is a chunk of data. It can be either keyed or unkeyed.

A keyed container is a dictionary. It contains values that are referenced by keys.

    "name": "Charlotte Grote",
    "occupation": "solver"

An unkeyed container is an array. It contains a list of values that can be accessed by index.

    "Charlotte Grote",
    "Shauna Wickle",
    "Midred Haversham",
    "Linton Baxter",
    "Jack Finch",
    "Sonny Craven"

Keyed and unkeyed containers can be combined in an individual JSON file.

The code

decoder.container(keyedBy: CodingKeys.self)

is indicating that you are trying to extract a keyed container (i.e., a dictionary) from some JSON and that the keys used in that dictionary correspond to the CodingKeys enum used in the struct that this init method belongs to.


You could always try reading apple's documentation to see if it helps solidify some things. However, I usually find Paul's approches to be much easier to read and digest.

If you look at the documentation for the Decoder protocol, you will see that container(keyedBy:) is listed as an instance method of it. That means that container(keyedBy:) is basically a function that you can call on any instance of Decoder that you create.

Then, if you look at the documentation for the container(keyedBy:) function, you can see its full declaration. Although, it might look a bit confusing.

func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey

I'm not sure if you have reached the part in the course that covers Type Generics yet. But this basically says that the container(keyedBy:) function takes some type of CodingKey as a parameter, and returns that same type of KeyedDecodingContainer.

So, in your example...

let container = try decoder.container(keyedBy: CodingKeys.self)

we are giving it CodingKeys.self as a parameter, and it will return a KeyedDecodingContainer based on that.

The KeyedDecodingContainer is basically just a container holding keys and the encoded values associated with them. You can think of it like a dictionary that might end up looking something like this...

    id: 0100010101011001010101010010001111,
    name:  000110101110110010101010101001010101010100101010,
    age: 1101001011101010010101010101001

So, when you call the .container(keyedBy:) function, it will return something like what is shown above. Notice that the values associated with the keys are not necessarily UUID, String, or Int. Instead, they are just some type of encoded data.

That's why we have to use this afterward...

name = try container.decode(String.self, forKey: .name)

That basically says, "Take all those ones and zeroes stored in the .name key of the container, and try to see if you can make a String out of it them. If you can, then store it in the name variable."


Just realized I forgot the third kind of container available when using Codable: single-value container. That contains, as one might expect, a single value, like an integer, a string, a date, etc.

So, to sum up:

01: {
02:     "coordinates": [
03:         {
04:           "latitude": 37.332,
05:           "longitude": -122.011
06:         },
07:         [-122.011, 37.332],
08:         "37.332, -122.011"
09:     ]
10: }
  • Line 01 starts a keyed container. It has one item with a key of "coordinates".
  • Line 02 starts an unkeyed container. It has 3 items.
  • Line 03 starts another keyed container. It has two items: "latitude" and "longitude".
  • Line 07 is an unkeyed container with two items.
  • Line 08 is a single-value container with one item, a string.

And, technically, every keyed container and unkeyed container holds a number of single-value containers to store their values.

If your Codable structs don't use any custom (en|de)coding, you won't need to worry about any of this because it will just work. But if you want to do any custom (en|de)coding, you will definitely need to know all about this stuff. It can also be useful when (en|de)coding enums.

Something I have found most helpful is the Flight School Guide to Swift Codable, which used to cost but is now available for free download. (The sample JSON I annotated above comes from that book, in fact.) It contains numerous examples of Codable tricks and information. Including using Codable to read from a JSON API, to work with UserDefaults and Core Data, and how to define your own encoders and decoders!


Can someone explain String.self -- why that versus self.string or similar?


String.self is referring to the String type. You are telling the decoder or encoder what type you are de|encoding.


Hacking with Swift is sponsored by Judo

SPONSORED Let’s face it, SwiftUI previews are limited, slow, and painful. Judo takes a different approach to building visually—think Interface Builder for SwiftUI. Build your interface in a completely visual canvas, then drag and drop into your Xcode project and wire up button clicks to custom code. Download the Mac App and start your free trial today!

Try now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.