Design a 3-8 Decoder Using Only 1-2 Decoders With Enable
What else can Decodable do?
Optional keys in Decodable
You can mark the variables as optional for which the JSON object does not contain the value. In below example, the JSON response does not send the postKey. JsonDecoder ensures that when the variable is marked as optional, it checks the value for the key in a JSON object and then set its value if present.
// MARK: - PhotoFeed
struct PhotoFeed: Decodable {
let id, photoTnURL, photoURL, photoURLScaled: String
let curated: Bool
let postKey: String?
} CodingKey
CodingKey tells the JSONDecoder to map the keys present in the container with the assigned variables. The above API response has id and photoTnURL, which does not tell what exactly the variable represents. This can be fixed with CodingKey. So we rename the keys id →feedId and photoTnURL → thumbnailUrlString
// MARK: - PhotoFeed
struct PhotoFeed: Decodable {
let feedId: String // Renamed from id
let thumbnailUrlString: String // Renamed from photoTnURL
let curated: Bool
let photoURL, photoURLScaled: String
let postKey: String enum CodingKeys: String, CodingKey {
case feedId = "id"
case thumbnailUrlString = "photoTnURL"
case curated, photoURL, photoURLScaled, postKey
}
}
Handle Nested Data
Let's say the API response starts sending you the location along with the feed. You can add the location in your data-model which will conform to Decodable. You can add the new Location struct in your PhotoFeed or as a new struct outside the PhotoFeed.
// MARK: - PhotoFeed
struct PhotoFeed: Decodable {
let feedId: String
let thumbnailUrlString: String
let curated: Bool
let photoURL, photoURLScaled: String
let postKey: String
let location: Location struct Location: Decodable {
var latitude: Double
var longitude: Double enum CodingKeys: String, CodingKey {
case latitude = "lat"
case longitude = "long"
}
}
enum CodingKeys: String, CodingKey {
case feedId = "id"
case thumbnailUrlString = "photoTnURL"
case curated, photoURL, photoURLScaled, postKey, location
}
}
Flatten out JSON nested properties
JSONDecoderwill help you iterate through all the container values. Use decoder.container(keyedBy:) on the decoder to get all the values present in the CodingKey. Similarly nestedContainer(keyedBy: forKey:) will allow you to iterate through the nested container. Using these methods you can iterate over all the keys in the decoder. Let's see this through an example to flatten out the structure
// MARK: - PhotoFeed
struct PhotoFeed: Decodable {
let feedId: String
let thumbnailUrlString: String
let curated: Bool
let photoURL, photoURLScaled: String
let postKey: String
let latitude: Double
let longitude: Doubleenum CodingKeys: String, CodingKey {
case location
case feedId = "id"
case thumbnailUrlString = "photoTnURL"
case curated, photoURL, photoURLScaled, postKey
}enum LocationKeys: String, CodingKey {
// MARK: - init with decoder
case latitude = "lat"
case longitude = "long"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self) let location = try values.nestedContainer(keyedBy: LocationKeys.self, forKey: .location)
latitude = try location.decode(Double.self, forKey: .latitude)
longitude = try location.decode(Double.self, forKey: .longitude) feedId = try values.decode(String.self, forKey: .feedId)
thumbnailUrlString = try values.decode(String.self, forKey: .thumbnailUrlString)
curated = try values.decode(Bool.self, forKey: .curated)
photoURL = try values.decode(String.self, forKey: .photoURL)
photoURLScaled = try values.decode(String.self, forKey: .photoURLScaled)
postKey = try values.decode(String.self, forKey: .postKey)}
}
Decoding strategies
KeyDecodingStrategy:
Sometimes the JSON response not always follows the camelCase naming convention. There is a good chance that you may have a response that follows snake_case.
We can set the decoding strategy that determines how coding keys are decoded from JSON. Let's take an example to solve this:
1.useDefaultKeys: It's the default strategy. JsonDecoder will use the same variable names for decoding
2.convertFromSnake: It will convert the JSON keys from snake-caseš to camel-caseš« keys present in your data-model
// MARK: - PhotoFeed
struct PhotoFeed: Decodable {
let feedId: String
let photoTnUrl: String
let curated: Bool
let photoUrl, photoUrlScaled: String
let postKey: String
} let data = json.data(using: .utf8)!
let jsonDecoder = JSONDecoder()
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
let photoFeed = try! jsonDecoder.decode(PhotoFeed.self, from: data)
3.custom: You can have your custom implementation which returns the correspondingCodingKey present in your data-model. The below data-model has keys which have youtube prefixed before every key present in JSON. Using custom decoding strategy, we can remove the prefixed stringyoutube from every JSON object key so it maps to the variable in PhotoFeed.
Decoding Dates
JsonDecoder supports decoding dates from the JSON response. Here is a list of supported date decoding strategies.
1.deferredToDate: Number of seconds elapsed since 1st Jan 2001 represented in double. A very rare chance you would be using this.
2. iso8601: This is the most widely used date-format. Use this link to understand more about date-format used under iso8601
3. formatted(DateFormatter): You can add a custom DateFormatter with required dateFormat
4.custom((Decoder) -> Date): You can write custom code for parsing your date. Let's say you have a bad JSON containing two date formats, here is a quick way to resolve it using .custom decoding strategy
5.millisecondsSince1970: It decodes date in milliseconds since midnight UTC on January 1st, 1970
6.secondsSince1970: Decodes date in seconds since midnight UTC on January 1st, 1970
Decoding Raw Data
JsonDecoder supports strategies for decoding your raw data. Here is a list of supported data decoding strategies
1.base64 : decodes data using Base 64 decoding
2.custom((Decoder) -> Data) : decodes data using a custom function implemented by you.
By now you already got a gist of how the default custom decoding works and how would you use them. Still find it difficult to understand, comment below and I will add gist for you
Decoding Exceptional Numbers
This strategy is used by a JsonDecoder when it encounters exceptional floating-point values. In your lifetime you must have encountered when your server returns an invalid "NaN". Similarly how to handle +ve infinity and -ve infinity values (which you might have never encountered), if not handled this would just CRASH š„ your app.
Here is how you handle nan, +veInfinity and -veInfinity
Design a 3-8 Decoder Using Only 1-2 Decoders With Enable
Source: https://medium.com/flawless-app-stories/complete-guide-to-codable-decodable-b1ff696da24f
0 Response to "Design a 3-8 Decoder Using Only 1-2 Decoders With Enable"
Postar um comentƔrio