如何从 iOS Swift Codable 中的 API 响应通知或打印模型类上缺少的密钥?
Posted
技术标签:
【中文标题】如何从 iOS Swift Codable 中的 API 响应通知或打印模型类上缺少的密钥?【英文标题】:How to notify or print for missing key on model class from API response in iOS Swift Codable? 【发布时间】:2019-12-20 17:38:45 【问题描述】:我有一个来自 API 的 JSON 响应,如下所示,
先前的 JSON 响应:
[
"EmployeeId": 711,
"FirstName": "Steve",
"LastName": "Jobs"
,
"EmployeeId": 714,
"FirstName": "John",
"LastName": "Doe"
]
同样的模型类有以下代码
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?
【问题讨论】:
没有报错,解析成功.. 当您有可用的“新”属性时,您会尝试收到警告? 我只是想在我的 Xcode 控制台或任何其他方式上通知或打印丢失的键 @CZ54 你能告诉我工作答案如何实现吗? 这是您需要与主要拥有/发布该 API 的人进行的讨论,也许他们会以某种方式传达他们的更改。 【参考方案1】:您可以执行以下操作:
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"
【讨论】:
非常好的解决方案。但是如果检查失败,你应该抛出DecodingError
以及 JSONSerialization
错误
这不是最初的要求,但可以改进
@CZ54 非常感谢,就我的问题而言,工作正常,但是嵌套 Codable 类有什么解决方案吗?例如:让部门:部门? where class Department: Codable let deptId: Int?让部门名称:字符串?如果响应位置键将添加到部门模型类中,则上述解决方案可能不起作用,在这种情况下也请帮助
@CZ54 您现在可以查看我更新的问题吗?
这不是一个非常有用的解决方案,它仅适用于***对象,因此如果您有一组对象或子对象,它将失败。如果您使用CodingKey
修改属性名称,它也会失败。所以总而言之,这是一个非常有限的解决方案【参考方案2】:
您可以实现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!")
【讨论】:
如果进一步添加更多键值对会怎样?问题是关于识别 API 中所做的更改。 这就是问题所在。这就是 OP 想知道的。 @Kamran 不是这样,请再次参考问题以获得更好的理解。以上是关于如何从 iOS Swift Codable 中的 API 响应通知或打印模型类上缺少的密钥?的主要内容,如果未能解决你的问题,请参考以下文章
Swift IOS 无法使用 Codable 访问 json 数组数据