[英]How to discriminate while decoding using Codable Protocol in Swift?
我正在使用 Swift 的 Codable 協議。 我已經分享了代碼。
我希望 Employee 類中的變量 boss 根據 Person 類中的 personType String 獲取類型。 我想使用 personType 作為鑒別器。 根據 personType 值,來自服務器的響應每次都會不同。
在 Employee 類中,我用 Person 類型聲明了 boss 變量。 如果 Person 類中的 personType 字符串是“Employee”,我希望它對 Employee 類型進行解碼,如果 personType 字符串是“Boss”,則對 Boss 類型進行解碼。 如果它為空,我只是想讓它解碼為 Person 類型。
任何幫助將非常感激。
public class Person: Codable {
public let address: String
public let age: Int
public let name: String
public let uid: String
public let personType: String?
private enum CodingKeys: String, CodingKey {
case address
case age
case name
case uid
case personType
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
address = try container.decode(String.self, forKey: .address)
age = try container.decode(Int.self, forKey: .age)
name = try container.decode(String.self, forKey: .name)
uid = try container.decode(String.self, forKey: .uid)
personType = try container.decodeIfPresent(String.self, forKey: .personType)
}
}
public class Employee: Person {
public let department: String
public let dependents: [Person]?
public let salary: Int
public let workingDays: [Days]
public var boss: Person?
private enum CodingKeys: String, CodingKey {
case department
case dependents
case salary
case workingDays
case boss
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
department = try container.decode(String.self, forKey: .department)
dependents = try container.decode([Person].self, forKey: .dependents)
salary = try container.decode(Int.self, forKey: .salary)
workingDays = try container.decode([Days].self, forKey: .workingDays)
boss = try container.decode(Person.self, forKey: .boss)
try super.init(from: decoder)
}
}
public class Boss: Employee {
let promotedAt: Double
let assistant: Employee?
enum CodingKeys: String, CodingKey {
case promotedAt
case assistant
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
promotedAt = try container.decode(Double.self, forKey: .promotedAt)
assistant = try container.decodeIfPresent(Employee.self, forKey: .assistant)
try super.init(from: decoder)
}
}
例如,在以下響應中,在 boss 部分,personType 設置為“Boss”。 所以應該解碼為Boss類型。 如果是'Employee',它應該自動解碼為Employee,或者如果它為null,則應該解碼為'Person'。
{ name: 'Shahid Khaliq',
age: 5147483645,
address: 'H # 531, S # 20',
uid: '123321',
salary: 20000,
department: 'Software Development',
workingDays: [ 'Monday', 'Tuesday', 'Friday' ],
boss:
{ personType: 'Boss',
assistant: null,
name: 'Zeeshan Ejaz',
age: 5147483645,
address: 'H # 531, S # 20',
uid: '123321',
birthday: '1994-02-13',
birthtime: '1994-02-13T14:01:54.000Z',
salary: 20000,
department: 'Software Development',
joiningDay: 'Saturday',
workingDays: [ 'Monday', 'Tuesday', 'Friday' ],
dependents: null,
hiredAt: 'Sun, 06 Nov 1994 08:49:37 GMT',
boss: null,
promotedAt: 1484719381 },
dependents: null,
hiredAt: 'Sun, 06 Nov 1994 08:49:37 GMT',
personType: null }
需要根據您發布的當前回復更改模型
public class Employee: Person {
public let department: String
public let dependents: [Person]?
public let salary: Int
public let workingDays:[String] //[Days]
public var boss: Person?
private enum CodingKeys: String, CodingKey {
case department
case dependents
case salary
case workingDays
case boss
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
department = try container.decode(String.self, forKey: .department)
//dependents = try container.decode([Person].self, forKey: .dependents)
dependents = try container.decodeIfPresent([Person].self, forKey: .dependents)
salary = try container.decode(Int.self, forKey: .salary)
// workingDays = try container.decode([Days].self, forKey: .workingDays)
workingDays = try container.decode([String].self, forKey: .workingDays)
// boss = try container.decode(Person.self, forKey: .boss)
boss = try container.decodeIfPresent(Person.self, forKey: .boss)
try super.init(from: decoder)
}
}
這里在幾個屬性中添加了decodeIfPresent ,因為它根據當前響應為空
在解碼時,您可以使用不同的東西,我使用 SwiftJSON 使代碼更具可讀性,
// i have saved response in Response.JSON file so can change response as per need while testing below code.
let file = Bundle.main.path(forResource: "Response", ofType: "JSON")
let dataURL = URL(fileURLWithPath: file!)
let data = try! Data(contentsOf: dataURL)
let jsonData = try! JSON(data: data)
//here JSON is struct which is part of SwiftyJSON
print("jsondata \(jsonData)")
do {
let bossDict = jsonData["boss"]
let dataBoss : Data = try! bossDict.rawData()
let bossType = bossDict["personType"].string
if let type = bossType {
if type == "Boss"{
let bossObj = try! JSONDecoder().decode(Boss.self, from: dataBoss)
print("boss name \(String(describing: bossObj.name))")
bossObj.listPropertiesWithValues()
}else{
// type == "Employee"
let emplyeeObj = try! JSONDecoder().decode(Employee.self, from: dataBoss)
print("Employee name \(String(describing: emplyeeObj.name))")
emplyeeObj.listPropertiesWithValues()
}
}else{
//type = nil
}
}catch{
print("exception \(error)")
}
您可以在鏈接DemoCodable下載相同的工作演示
我會在Employee
類中的init(from decoder:)
末尾添加一個 switch 語句
switch personType {
case "Boss":
boss = try container.decode(Boss.self, forKey: .boss)
case "Employee":
boss = try container.decode(Employee.self, forKey: .boss)
default:
boss = nil
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.