问题
Given a JSON object with nested object structure that looks like this:
{
"users":[
{
"user":{
"name":"Adam",
"age":25
},
"address":{
"city":"Stockholm",
"country":"Sweden"
}
},
{
"user":{
"name":"Lilly",
"age":24
},
"address":{
"city":"Copenhagen",
"country":"Denmark"
}
}
]
}
How can one implement correct Decodable
implementation for an object that looks like this.
struct User {
struct Address {
let city: String
let country: String
}
let name: String
let age: Int
let address: Address
}
Notice that the Swift struct contains a nested struct Address
, while the JSON object has address
in a separate object. Is it possible to create the Decodable
implementation that handles this scenario?
I've tried various approaches, but all of them included creation of intermediary objects that would later map to the User
struct. Is it possible to create an implementation that doesn't involve creation of these intermediary objects?
回答1:
You can use a custom decoder so that you don't have to create the other objects.
struct User: Decodable {
let name: String
let age: Int
let address: Address
struct Address: Decodable {
let city: String
let country: String
}
enum CodingKeys: String, CodingKey {
case user
case address
}
enum UserKeys: String, CodingKey {
case name
case age
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let user = try container.nestedContainer(keyedBy: UserKeys.self, forKey: .user)
name = try user.decode(String.self, forKey: .name)
age = try user.decode(Int.self, forKey: .age)
address = try container.decode(Address.self, forKey: .address)
}
}
So putting your data into a playground
let data = """
{
"users":[
{
"user":{
"name":"Adam",
"age":25
},
"address":{
"city":"Stockholm",
"country":"Sweden"
}
},
{
"user":{
"name":"Lilly",
"age":24
},
"address":{
"city":"Copenhagen",
"country":"Denmark"
}
}
]
}
""".data(using: .utf8)!
You can decode like this:
let decoder = JSONDecoder()
let result = try! decoder.decode([String:[User]].self, from: data)
Or you can create a Users struct so that you don't have to deal with dictionaries
struct Users: Decodable {
let users: [User]
}
let decoder = JSONDecoder()
let result = try! decoder.decode(Users.self, from: data)
回答2:
Did you mean to flatten the struct
using computed properties like this:
struct User: Codable {
struct UserDetail: Codable {
let name: String
let age: Int
}
struct Address: Codable {
let city: String
let country: String
}
let user: UserDetail
let address: Address
var name: String { user.name}
var age: Int { user.age }
var city: String { address.city }
var country: String { address.country }
}
print(user.name, user.age, user.city, user.country) // all the properties accessible within User struct
来源:https://stackoverflow.com/questions/62403333/flattened-objects-in-json-file-to-nested-object-structure-in-swift