[英]Parse JSON with different keys to same object using Codable in Swift
我收到來自不同 API 的以下 2 個響應
{
"id": "jdu72bdj",
"userInfo": {
"name": "Sudhanshu",
"age": 28,
"country": "India"
}
}
和
{
"profileId": "jdu72bdj",
"profileDetails": {
"name": "Sudhanshu",
"age": 28,
"country": "India"
}
}
這與使用Swift
語言的iOS development
有關。 基本上 object 結構相同,但鍵不同。 我正在使用Codable
解析這些,但我想不出使用相同結構解析的方法。 我能想到的就是像這樣制作2個不同的結構 -
public struct Container1: Codable {
public let id: String
public let userInfo: UserProfile?
}
和
public struct Container2: Codable {
public let profileId: String
public let profileDetails: UserProfile?
}
他們都使用通用的UserProfile
結構。
public struct UserProfile: Codable {
public let name: String?
public let age: Int?
public let country: String?
}
有沒有一種方法可以為兩個響應使用一個通用容器結構來解析來自 2 個不同鍵的響應。 我不想要 Container1 和 Container2 因為它們都有相同的結構。
有什么建議么?
一種解決方案是使用自定義密鑰解碼策略,使用 Apple 文檔中的CodingKey
實現。 這個想法是將 map 兩個 json 消息的鍵與將用於兩個消息的結構容器的屬性。
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .custom({ keys in
let key = keys.last!.stringValue
switch key {
case "id", "profileId":
return AnyKey(stringValue: "id")!
case "userInfo", "profileDetails":
return AnyKey(stringValue: "details")!
default:
return keys.last!
}
})
CodingKey
的自定義實現在哪里
struct AnyKey: CodingKey {
var stringValue: String
var intValue: Int?
init?(stringValue: String) {
print(stringValue)
self.stringValue = stringValue
intValue = nil
}
init?(intValue: Int) {
self.stringValue = String(intValue)
self.intValue = intValue
}
}
然后使用以下結構以相同的方式解碼兩個 json 消息
struct Container: Codable {
let id: String
let details: UserProfile
}
let result = try decoder.decode(Container.self, from: data)
您可以從解碼器中使用自己的 init
struct UniversalProfileContainer: Decodable {
struct UserProfile: Decodable {
var name: String
var age: Int
var country: String
}
enum CodingKeys: String, CodingKey {
case id = "id"
case profileId = "profileId"
case userInfo = "userInfo"
case profileDetails = "profileDetails"
}
let id: String
let profile: UserProfile
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
id = try container.decode(String.self, forKey: .id)
} catch {
id = try container.decode(String.self, forKey: .profileId)
}
do {
profile = try container.decode(UserProfile.self, forKey: .userInfo)
} catch {
profile = try container.decode(UserProfile.self, forKey: .profileDetails)
}
}
}
let first = """
{
"id": "jdu72bdj",
"userInfo": {
"name": "Sudhanshu",
"age": 28,
"country": "India"
}
}
"""
let second = """
{
"profileId": "jdu72bdj",
"profileDetails": {
"name": "Sudhanshu",
"age": 28,
"country": "India"
}
}
"""
let response1 = try? JSONDecoder().decode(UniversalProfileContainer.self,
from: first.data(using: .utf8)!)
let response2 = try? JSONDecoder().decode(UniversalProfileContainer.self,
from: second.data(using: .utf8)!)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.