Reputation: 813
I am trying the following code but it is throwing an exception
import Foundation
class SomeBaseClass: Codable {
let someInt: Int?
let someString: String?
init(someInt: Int,someString:String) {
self.someInt = someInt
self.someString = someString
}
init(someBaseClass: SomeBaseClass) {
self.someString = someBaseClass.someString
self.someInt = someBaseClass.someInt
}
}
class Person: SomeBaseClass {
let firstName: String?
let lastName: String?
init(firstName: String,lastName:String,someBaseClass: SomeBaseClass) {
self.firstName = firstName
self.lastName = lastName
super.init(someBaseClass: someBaseClass)
}
enum CodingKeys: String, CodingKey {
case firstName,lastName
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
firstName = try container.decode(String.self, forKey: .firstName)
lastName = try container.decode(String.self, forKey: .lastName)
try super.init(from: container.superDecoder())
}
}
let json = """
{
"firstName":"John",
"someInt":2
}
"""
let jsonData = json.data(using: .utf8)!
do {
let personObject = try JSONDecoder().decode(Person.self, from: jsonData)
dump(personObject)
} catch let error as NSError {
print(error)
}
It crashes with the following error
Error Domain=NSCocoaErrorDomain Code=4865 "No value associated with key CodingKeys(stringValue: "lastName", intValue: nil) ("lastName")." UserInfo={NSDebugDescription=No value associated with key CodingKeys(stringValue: "lastName", intValue: nil) ("lastName")., NSCodingPath=( )}
I know lastName
is missing in the JSON and i have marked it as optional but it does not work like how it works for structs
Is there a simple method to do the same ?
Upvotes: 1
Views: 223
Reputation: 51871
You should use decodeIfPresent
for your optional properties
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
firstName = try container.decodeIfPresent(String.self, forKey: .firstName)
lastName = try container.decodeIfPresent(String.self, forKey: .lastName)
try super.init(from: decoder)
}
Also note the change to super that was needed to avoid another error. You can also change your catch slightly from
} catch let error as NSError {
print(error)
}
to simply
} catch {
print(error)
}
Upvotes: 2