JSONDecoder will decode the JSON data into Car struct, Car.self tells JSONDecoder that this JSON contains properties of Car struct and decode it into Car struct.

There is a try? in front of JSONDecoder as the data you pass to the decoder might be an invalid JSON, or not even a JSON at all. When these happen, JSONDecoder().decode method will throw an error. The Try? is used to catch error if error is thrown.

Notice the JSONDecoder().decode([Car].self, from: data) , [Car] means array of Car, [Car].self tells the JSONDecoder that the JSON Data contains type of Array of Car struct. If Car conforms to Decodable, [Car] is Decodable and can be decoded as well.

Parse JSON from non-root key

Lets use back the Car struct:

struct Car: Decodable
{
let name: String
let horsepower: Int
}

Similar to previous JSON, we have an array of cars, but now they are inside the key of "cars" instead of on the root (most outer) of the JSON :

[String: [Car]].self tells the JSONDecoder to decode it into a dictionary of array of cars.

Now we know that JSONDecoder().decode([String: [Car]].self, from: data) will parse the JSON data into a dictionary of array of cars like this : ["cars": [carOne, carTwo]].

To access the cars array from the dictionary, we use carsArrDict["cars"]!. "cars" is the key in the JSON.

There is an exclaimation mark behind as compiler doesn't know if the dictionary has the key "cars", if the dictionary doesn't have the key "cars", it will return nil when we call carsArrDict["cars"]. Since we are sure that the JSON contain the key "cars", we can force unwrap it using !.

Parse JSON key into different property name

This time we will add a new property manufacturedAt to the Car struct to indicate which year the car was manufactured :

By default, if you didn't declare the CodingKeys enum (we didn't declare this for the past few examples), compiler will auto generate the enum CodingKeys for you, which will map all the Keys of JSON directly to the Car struct without change (eg: 'name' from JSON to 'name' of Car struct, 'horsepower' from JSON to 'horsepower' of Car struct).

Since we are not using the default direct mapping, as we have a different property name than the JSON key ('manufactured_at' from JSON to 'manufacturedAt' of Car struct). We will have to override the default CodingKeys by declaring it explicitly:

Note 2: If we decide to override the CodingKeys enum, we have to specify all of the properties of a struct / class in CodingKeys enum. Even if we missed just one, compiler will complain :

The error message Type 'Car' does not conform to protocol 'Decodable' doesn't inform you that the missing property in the CodingKeys needs to be filled. This might cause confusion for developer who are new to Decodable / Codable protocol 😞.

Parsing a nested struct / object is straightforward and no additional code is required on the parsing part, just add the child struct / object property to the parent.

Note:
I have removed the manufacturedAt property from Car struct to isolate away the CodingKeys from the previous section, in order to simplify the explanation of this section.

If you are wondering how to set the CodingKeys for a struct which have a child struct, you just need to specify the property of the parent struct (no need to worry about property of the child struct), like this :

Notice that fuel_tank_capacity key is absent for the Tesla Model car, if we run the same parsing code, we will still get a nice output as compiler will set the property value as nil if the property key doesn't exist in the JSON.

Cheatsheet

Phew this is a long post 😅.
To save you time from Googling "Parse json array swift" etc, I have made a handy cheatsheet that you can quickly refer for different cases of JSON parsing I have mentioned above.

Get the Cheatsheet for parsing JSON in Swift

Save yourself from googling "parse json array swift" every time you deal with JSON