All About Codable in Swift (Part 2)
--
This is the continuation of part 1. In this part we will cover the following topics
- Swift Models Generator tools
- Working With Deep JSON Hierarchies
- Working With Date
- Working With Enum and Url Data Type
- Codable Ability to Realm Models
- Working with class inheritance
Swift Models Generator
This is the tool that generate json response into swift classes highly recommended. Just paste your json response and get your swift model classes
Working With Deep JSON Hierarchies
As shown in Figure 1 we have json with deep hierarchy
As shown in Figure 2 our structure is same as json response so we don’t need to do extra efforts. Like User
expect array of Custom Company
model and Company
model expect array of SubCompany
model structure
As shown in Figure 3 magic of Codable is working automatically
Now if your json has changed something as shown in Figure 4, where company data were added after extra layer under key
and due to this there is a mismatch between our model and the json.
As shown in Figure 5 we got crash while unwrapping optional since some of the json don’t parse because of the mismatch between our model and json
So to solve this problem we need to write custom decoding and as shown in Figure 6 we used nested keyed containers for key
in this case as this key add one more level to access our company model. We did the following things
- Create your top-level coding keys.
- Create another set of coding keys, which you’ll use to create another container.
- Decode the
name
andid
the way you’re used to. - Create a nested container
nestedContainer(keyedBy:forKey:)
and decodecompany
with it.
For the encoding part it will create json same as our model and as shown in Figure 7 after encoding it removed key
from it, so to add this nested hierarchy level we need to do custom encoding
As shown in Figure 8 we wrote custom encoding , now it added key
in our final json what the server expect
Working With Date
JSON has no data type to represent dates, so these are serialized into some representation that the client and server have to agree on. Typically this is done with ISO 8601 date formatting and then serialized as a string.
As shown in Figure 9 we want to parse dob
key value in date
type which is coming in Int
as UNIX millisecond timestamp in json so parsing will failed
As shown in Figure 10 by using dateDecodingStrategy
we successfully parsed it. It convert date in milliseconds which is Int
to proper Date
type
dateDecodingStrategy →
The strategy to use in decoding dates. Means while decoding of a model if it find any property asDate
dataType it tries to decode according to the strategy defined
You can pass your own formatter as well as shown in Figure 11. Most of the time you will use this if both backend and frontend will use this format to communicate about the DateTime format in overall application because you write the decoding logic with generic in single time
As shown in Figure 12 since we define millisecondsSince1970
as a dateDecodingStrategy.
So for dob
we implement custom decoding and dobInMili
will be easily parse by our dateDecodingStrategy
Working With enum
As shown in Figure 13 by conforming to Codable
protocol , decoder automatically parse String
and convert it to enum
type with rawvalue.
Working With Url
As shown in Figure 13.1 Codable automatically convert string
into Url
Working With Realm Model
Realm is a cross platform mobile object database. If you want to learn more about Realm see this link where I wrote a whole series on this. You should look first then come again because here our focus only on parsing
As shown in Figure 14 decoding still working but there are couple of things we change in order to use Realm model as a decodable
- Replaces struct with class unless you will get this error “cannot inherit from class ‘Object` )”
- Move the model to outside to the controller
As shown in Figure 15 as we added RealmOptional
type , since codable don’t know how to parse this type of datatype it will throw an error and unable to show its magic. to solve this problem we wrote custom decoding and took the value as an Int and assign it to the realm optional . Note convenience required init is used. If you want to learn more about Initialization hell see the documentation
Since Realm doesn’t support optional lists. You could just use empty by default. While decoding first decode in temporary variable if key may or may not exists then assign it to. Note let companies = List<Company>()
we used let since it’s a reference type appending value will not mutate it
Working With Class Inheritance
We get the Codable conformance by inheriting from the user class, but what happens if we try to encode an instance of GoldUser
? . Well that’s not what we wanted. As it turns out the auto-generated implementation doesn’t quite work with subclasses. So we’ll have to customize the encode/decode methods again.
Writing the custom decoding in subclass only, will not able to decode the super class property since decoder is expecting coding keys defined keys
As shown in Figure 19 we solved this issue by custom decoding in base class as well and called super.decoder
in sub class. There is a bug previously where calling super.init(from: decoder) causes EXC_BAD_ACCESS when attempting to do so. At that point apple suggested
“If a shared container is desired, it is still possible to call `super.encode(to: encoder)` and
`super.init(from: decoder)`, but we recommend the safer containerized option.”
Now it is fixed so no worry.
If we have a base class model under some key in json we can superDecoder
method. This produces the super-class decoding underneath this key: ”user”