Swift Codable Decode Manually Optional Variable
Age is optional:
let age: String?
So try to decode in this way:
let age: String? = try values.decodeIfPresent(String.self, forKey: .age)
Best approach to create Non-optional Codable with `default values` in swift
You can implement a custom decoder with default values:
class CompanyInfo : Codable {
var NameEn: String
var CityEn: String
var Website: String
var Email: String
var Phone: String
var Fax: String
required init(from decoder: Decoder) throws {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.NameEn = try container.decodeIfPresent(String.self, forKey: .NameEn) ?? "Default"
self.CityEn = try container.decodeIfPresent(String.self, forKey: .CityEn) ?? "Default"
self.Website = try container.decodeIfPresent(String.self, forKey: .Website) ?? "Default"
self.Email = try container.decodeIfPresent(String.self, forKey: .Email) ?? "Default"
self.Phone = try container.decodeIfPresent(String.self, forKey: .Phone) ?? "Default"
self.Fax = try container.decodeIfPresent(String.self, forKey: .Fax) ?? "Default"
}
}
}
Unrelated to question, but important Note:
In Swift, only Types
names should start with a capital letter. If you continue naming variables like this, you will have a serious refactoring issue one day if you decide to use CoreData
or working with other Swift developers.
Codable: give a default value to a new non-optional property
You can implement required init and give it a default value:
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let title = try container.decodeIfPresent(String.self, forKey: .title) ?? "Default title"
self.title = title
let baseDecoder = try container.superDecoder(forKey: .id)
try super.init(from: baseDecoder)
}
Error decoding data with Codable even though parameters are optional
When you implement init(from:)
manually you need to use the decodeIfPresent(_:forKey:)
variant for optional properties. The decode(_:forKey:)
method throws an error if a nullable field in the JSON data is absent whereas the decodeIfPresent(_:forKey:)
method just returns nil.
Try this:
init(from decoder: Decoder) throws {
enum DecodingKeys: CodingKey {
case minutes
}
let container = try decoder.container(keyedBy: DecodingKeys.self)
minutes = try container.decodeIfPresent(Int.self, forKey: .minutes)
}
What is difference between optional and decodeIfPresent when using Decodable for JSON Parsing?
There's a subtle, but important difference between these two lines of code:
// Exhibit 1
foo = try container.decode(Int?.self, forKey: .foo)
// Exhibit 2
foo = try container.decodeIfPresent(Int.self, forKey: .foo)
Exhibit 1 will parse:
{
"foo": null,
"bar": "something"
}
but not:
{
"bar": "something"
}
while exhibit 2 will happily parse both. So in normal use cases for JSON
parsers you'll want decodeIfPresent
for every optional in your model.
How to manually decode an an array in swift 4 Codable?
Your code doesn't compile due to a few mistakes / typos.
To decode an array of Int
write
struct Something: Decodable {
var value: [Int]
enum CodingKeys: String, CodingKey {
case value
}
init (from decoder :Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
value = try container.decode([Int].self, forKey: .value)
}
}
But if the sample code in the question represents the entire struct it can be reduced to
struct Something: Decodable {
let value: [Int]
}
because the initializer and the CodingKeys
can be inferred.
With JSONDecoder in Swift 4, can missing keys use a default value instead of having to be optional properties?
Approach that I prefer is using so called DTOs - data transfer object.
It is a struct, that conforms to Codable and represents the desired object.
struct MyClassDTO: Codable {
let items: [String]?
let otherVar: Int?
}
Then you simply init the object that you want to use in the app with that DTO.
class MyClass {
let items: [String]
var otherVar = 3
init(_ dto: MyClassDTO) {
items = dto.items ?? [String]()
otherVar = dto.otherVar ?? 3
}
var dto: MyClassDTO {
return MyClassDTO(items: items, otherVar: otherVar)
}
}
This approach is also good since you can rename and change final object however you wish to.
It is clear and requires less code than manual decoding.
Moreover, with this approach you can separate networking layer from other app.
Related Topics
Example of Dispatch_Once in Swift
Binary Operator '+' Cannot Be Applied to Two 'T' Operands
What's the Difference Between Class Methods and Instance Methods in Swift
Lazy Readonly Property in Swift
Load a Collada (Dae) File into Scnnode (Swift - Scenekit)
How Does Typecasting/Polymorphism Work with This Nested, Closure Type in Swift
How to Get Row Index in Swiftui List
How to Programmatically Change the Alpha of a Uivisualeffectview in a Navigationbar
Check If Any Property in an Object Is Nil - Swift 3
How to Make Apple Sign in Revoke Token Post Request
Weak VS Unowned in Swift. What Are the Internal Differences
How to Change the Uinavigationbar Title's Position
How to Make Rounded Corner Progress Bar in Swift
Cannot Read the Nfc Chip of the Epassport Using iOS13
Sending a Parameter Argument to Function Through Uitapgesturerecognizer Selector
iOS 11 Uirefreshcontrol with Navigationbar Largetitle and Searchcontroller Disappearing