Flattened objects in JSON file to nested object structure in Swift [duplicate]

怎甘沉沦 提交于 2021-02-10 15:10:05

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!