[英]Decode custom JSON with Decodable + Realm Swift
從服務器上,我返回了一個很大的JSON,看起來像這樣:
{
"id": "123",
"status": "ok",
"person": {
"administration": {
"name": "John"
}
},
"company": {
"name": "Test"
}
}
我有一個結構:
struct Info: Decodable, Object {
let id: String
let status: String
let personName: String
let companyName: String
}
它符合可解碼協議,並且也是一個對象(領域實體)。 我的問題是:我可以通過某種方式解碼personName中人的名字嗎? 類似於person.administration.name。
我希望最終的Realm Object成為扁平對象,並且幾乎所有字段都是字符串。
是否應該為Person / Company創建單獨的結構而不將其設置為Realm Objects,而在解碼方法中將相應的值設置為“ personName”?
let personName: String = try container.decode((Person.Administration.name).self, forKey: .personName)
您可以簡單地使用containers
通過Decodable
解碼嵌套的數據,即
struct Info: Decodable {
let id: String
let status: String
let personName: String
let companyName: String
enum CodingKeys: String, CodingKey {
case id, status
case person, administration
case company
case name
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decode(String.self, forKey: .id)
status = try values.decode(String.self, forKey: .status)
//Decoding personName
let person = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .person)
let administration = try person.nestedContainer(keyedBy: CodingKeys.self, forKey: .administration)
personName = try administration.decode(String.self, forKey: .name)
//Decoding companyName
let company = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .company)
companyName = try company.decode(String.self, forKey: .name)
}
}
例:
我已經解碼了您在上面提供的JSON
,即
if let data = json.data(using: .utf8) {
let info = try? JSONDecoder().decode(Info.self, from: data)
print(info)
}
它給出的輸出是:
(id: "123", status: "ok", personName: "John", companyName: "Test")
您可以根據CodingKeys
將所有不同級別的CodingKeys
分開。 為了簡單起見,我將它們保持在同一級別。
建議:嘗試將optional types
與Codable
一起Codable
。 這是因為API
響應可能是意外的。 而且,如果沒有得到任何預期的鍵值對,則在創建對象時可能最終得到nil
。
最好的做法是將要解析JSON的傳輸類型和代表存儲對象的類型分開。
但是,如果要使用此組合類型,則應執行以下操作:
struct Info: Decodable {
let id: String
let status: String
let personName: String
let companyName: String
// JSON root keys
private enum RootKeys: String, CodingKey {
case id, status, person, company
}
// Keys for "person" nested "object"
private enum PersonKeys: String, CodingKey {
case administration
}
// Keys for "administration" and "company"
private enum NamedKeys: String, CodingKey {
case name
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: RootKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.status = try container.decode(String.self, forKey: .status)
let personContainer = try container.nestedContainer(keyedBy: PersonKeys.self, forKey: .person)
let administrationContainer = try personContainer.nestedContainer(keyedBy: NamedKeys.self, forKey: .administration)
self.personName = try administrationContainer.decode(String.self, forKey: .name)
let companyContainer = try container.nestedContainer(keyedBy: NamedKeys.self, forKey: .company)
self.companyName = try companyContainer.decode(String.self, forKey: .name)
}
}
為了某種類型的安全性,我將密鑰分為三種不同的CodingKey
類型,以防止意外混淆。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.