繁体   English   中英

如何在iOS Swift Codable中通过API响应通知或打印模型类中缺少的键?

[英]How to notify or print for missing key on model class from API response in iOS Swift Codable?

我有一个来自API的JSON响应,如下所示,

以前的JSON响应:

[
  {
    "EmployeeId": 711,
    "FirstName": "Steve",
    "LastName": "Jobs"
  },
  {
    "EmployeeId": 714,
    "FirstName": "John",
    "LastName": "Doe"
  }
]

和model的模型类有以下代码

class EmployeeModel: Codable {

    let EmployeeId: Int?
    let FirstName: String?
    let LastName: String?
}

Swift Codable解析工作正常

do {
    let decodedResponse = try JSONDecoder().decode([EmployeeModel].self, from: response.rawData())
    print(decodedResponse)

} catch let jsonErr {
    print(jsonErr.localizedDescription)
}

但现在

最新的JSON响应

从API更改并添加一个MiddleName键作为响应,请参阅下面的屏幕截图,它也可以正常使用Swift Codable代码。 在此输入图像描述

但是如何在iOS Swift 5中通过API的JSON响应添加通知或打印MiddleName键?

更新问题

根据@ CZ54下面提供的答案,解决方案工作正常,但无法检查另一个派生类缺失键。 例如:

在此输入图像描述

// 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?
}

您可以执行以下操作:

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"

您可以实现initializer并检查key是否存在,如下所示,

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!")
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM