Here is my JSON
{
"id": 1,
"user": {
"user_name": "Tester",
"real_info": {
"full_name":"Jon Doe"
}
},
"reviews_count": [
{
"count": 4
}
]
}
Here is the structure I want it saved to (incomplete)
struct ServerResponse: Decodable {
var id: String
var username: String
var fullName: String
var reviewCount: Int
enum CodingKeys: String, CodingKey {
case id,
// How do i get nested values?
}
}
I have looked at Apple's Documentation on decoding nested structs, but I still do not understand how to do the different levels of the JSON properly. Any help will be much appreciated.
In order to solve your problem, you can split your
RawServerResponse
implementation into several logic parts.#1. Implement the properties and required coding keys
#2. Set the decoding strategy for
id
property#3. Set the decoding strategy for
userName
property#4. Set the decoding strategy for
fullName
property#5. Set the decoding strategy for
reviewCount
propertyComplete implementation
Usage
These guys already answered my question, but I just thought i'd post this link here which makes this a whole lot easier -> https://app.quicktype.io/#l=swift
Simply post your JSON response on the left hand pane, and watch your Models get generated on the right. This can help when youre just starting of.
Also you can use library KeyedCodable I prepared. It will require less code. Let me know what you think about it.
Rather than having one big
CodingKeys
enumeration with all the keys you'll need for decoding the JSON, I would advise splitting the keys up for each of your nested JSON objects, using nested enumerations to preserve the hierarchy:This will make it easier to keep track of the keys at each level in your JSON.
Now, bearing in mind that:
A keyed container is used to decode a JSON object, and is decoded with a
CodingKey
conforming type (such as the ones we've defined above).An unkeyed container is used to decode a JSON array, and is decoded sequentially (i.e each time you call a decode or nested container method on it, it advances to the next element in the array). See the second part of the answer for how you can iterate through one.
After getting your top-level keyed container from the decoder with
container(keyedBy:)
(as you have a JSON object at the top-level), you can repeatedly use the methods:nestedContainer(keyedBy:forKey:)
to get a nested object from an object for a given keynestedUnkeyedContainer(forKey:)
to get a nested array from an object for a given keynestedContainer(keyedBy:)
to get the next nested object from an arraynestedUnkeyedContainer()
to get the next nested array from an arrayFor example:
Example decoding:
Iterating through an unkeyed container
Considering the case where you want
reviewCount
to be an[Int]
, where each element represents the value for the"count"
key in the nested JSON:You'll need to iterate through the nested unkeyed container, getting the nested keyed container at each iteration, and decoding the value for the
"count"
key. You can use thecount
property of the unkeyed container in order to pre-allocate the resultant array, and then theisAtEnd
property to iterate through it.For example:
Another approach is to create an intermediate model that closely matches the JSON (with the help of a tool like quicktype.io), let Swift generate the methods to decode it, and then pick off the pieces that you want in your final data model:
This also allows you to easily iterate through
reviews_count
, should it contain more than 1 value in the future.