Plist with different dictionaries to a struct

Viewed 262

I have a plist which is an array of dictionaries. (root is array). Each dic have 2 values for sure : name, and icon as Strings. But some of them have more keys/values, some don't.

I am trying to read the array into a structure with :

struct Config: Decodable {
    private enum CodingKeys: String, CodingKey {
        case name, icon
    }

    let name: String
    let icon: String
}



func functionsStruct() -> Config {
    let url = Bundle.main.url(forResource: "FunctionsList", withExtension: "plist")!
    let data = try! Data(contentsOf: url)
    let decoder = PropertyListDecoder()
    return try! decoder.decode(Config.self, from: data)
}
  1. I read a dictionary, how to read an array of dictionaries and how to set up the structure.

  2. how to solve it that some dics have keys that others don't ?

2 Answers

For your first question :

I read a dictionary, how to read an array of dictionaries and how to set up the structure.

func functionsStruct() -> [Config] {
            let url = Bundle.main.url(forResource: "FunctionsList", withExtension: "plist")!
            let data = try! Data(contentsOf: url)
            let decoder = PropertyListDecoder()
            return try! decoder.decode([Config].self, from: data)
        }

As simple as that!!!

If you want an array of dictionaries, then you don't need to create your own Codable class. Arrays and dictionaries already implements Codable.

Just do:

func functionsStruct() -> [[String: String]] {
    let url = Bundle.main.url(forResource: "FunctionsList", withExtension: "plist")!
    let data = try! Data(contentsOf: url)
    let decoder = PropertyListDecoder()
    return try! decoder.decode([[String: String]].self, from: data)
}

Or use [[String: Any]] if the dictionary contains values other than strings.

And then you can access your name and icon like this:

let dicts = functionsStruct()
print(dicts[0]["name"])

However, I don't understand why you insist on using a dictionary. I strongly recommend you to stick with a Codable struct. You can make optional keys optional:

struct Config: Decodable {
    let name: String
    let icon: String
    let optionalKey1: String?
    let optionalKey2: String?
}

Their values will be nil if the key does not exist in the plist.

And you need to decode an array of Config, instead of just Config like you did:

return try! decoder.decode([Config].self, from: data)
Related