I have one JSON response from API as follows,
Previous JSON Response:
[
{
"EmployeeId": 711,
"FirstName": "Steve",
"LastName": "Jobs"
},
{
"EmployeeId": 714,
"FirstName": "John",
"LastName": "Doe"
}
]
and model class for same has following code
class EmployeeModel: Codable {
let EmployeeId: Int?
let FirstName: String?
let LastName: String?
}
for parsing with Swift Codable working fine
do {
let decodedResponse = try JSONDecoder().decode([EmployeeModel].self, from: response.rawData())
print(decodedResponse)
} catch let jsonErr {
print(jsonErr.localizedDescription)
}
but now the
Latest JSON Response
from API is changed and one MiddleName key is added in response see following screenshot and it is also working fine with Swift Codable code.
But how can I get notify or print that MiddleName key is now added on JSON response from API in iOS Swift 5?
UPDATE TO QUESTION
According to answer provided below by @CZ54, solution working fine but it is unable to check for another derived class missing key. For example:
// MARK:- LoginModel
class LoginModel: Codable {
let token: String?
let currentUser: CurrentUser?
}
// MARK:- CurrentUser
class CurrentUser: Codable {
let UserName: String?
let EmployeeId: Int?
let EmployeeName: String?
let CompanyName: String?
}
You can do the following:
let json = """
{
"name" : "Jobs",
"middleName" : "Bob"
}
"""
class User: Decodable {
let name: String
}
extension JSONDecoder {
func decodeAndCheck<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable {
let result = try self.decode(type, from: data)
if let json = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? [String: Any] {
let mirror = Mirror(reflecting: result)
let jsonKeys = json.map { return $0.0 }
let objectKeys = mirror.children.enumerated().map { $0.element.label }
jsonKeys.forEach { (jsonKey) in
if !objectKeys.contains(jsonKey) {
print("\(jsonKey) is not used yet")
}
}
}
return result
}
}
try JSONDecoder().decodeAndCheck(User.self, from: json.data(using: .utf8)!)
//will print "middleName is not use yet"
You can implement the initializer
and check the key
if it exists as below,
struct CustomCodingKey: CodingKey {
let intValue: Int?
let stringValue: String
init?(stringValue: String) {
self.intValue = Int(stringValue)
self.stringValue = stringValue
}
init?(intValue: Int) {
self.intValue = intValue
self.stringValue = "\(intValue)"
}
}
class EmployeeModel: Codable {
var EmployeeId: Int?
var FirstName: String?
var LastName: String?
private enum CodingKeys: String, CodingKey {
case EmployeeId, FirstName, LastName
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let allKeysContainer = try decoder.container(keyedBy: CustomCodingKey.self)
self.EmployeeId = try container.decodeIfPresent(Int.self, forKey: .EmployeeId)
self.FirstName = try container.decodeIfPresent(String.self, forKey: .FirstName)
self.LastName = try container.decodeIfPresent(String.self, forKey: .LastName)
let objectKeys = container.allKeys.map { $0.rawValue}
for key in allKeysContainer.allKeys {
if objectKeys.contains(key.stringValue) == false {
print("Key: " + key.stringValue + " is added!")
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.