type any? has no subscript members
When you subscript profile with "Addresses"
, you're getting an Any
instance back. Your choice to use Any
to fit various types within the same array has caused type erasure to occur. You'll need to cast the result back to its real type, [[String: Any]]
so that it knows that the Any
instance represents an Array
. Then you'll be able to subscript it:
func f() {
let address: [[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]]
let profile: [String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address]
guard let addresses = profile["Addresses"] as? [[String: Any]] else {
// Either profile["Addresses"] is nil, or it's not a [[String: Any]]
// Handle error here
return
}
print(addresses[0])
}
This is very clunky though, and it's not a very appropriate case to be using Dictionaries in the first place.
In such a situation, where you have dictionaries with a fixed set of keys, structs are a more more appropriate choice. They're strongly typed, so you don't have to do casting up and down from Any
, they have better performance, and they're much easier to work with. Try this:
struct Address {
let address: String
let city: String
let zip: Int
}
struct Profile {
let name: String
let age: Int
let addresses: [Address]
}
let addresses = [
Address(
address: "someLocation"
city: "ABC"
zip: 123
),
Address(
address: "someLocation"
city: "DEF"
zip: 456
),
]
let profile = Profile(name: "Mir", age: 10, addresses: addresses)
print(profile.addresses[0]) //much cleaner/easier!
You should re-think how you've chosen to construct adress
and profile
; see e.g. Alexander Momchliov's answer.
For the technical discussion, you could extract the Any
members of profile
that you know to contain [String: Any]
dictionaries wrapped in an Any
array; by sequential attempted type conversion of profile["Addresses"]
to [Any]
followed by element by element (attempted) conversion to [String: Any]
:
if let adressDictsWrapped = profile["Addresses"] as? [Any] {
let adressDicts = adressDictsWrapped.flatMap{ $0 as? [String: Any] }
print(adressDicts[0]) // ["Zip": 123, "City": "ABC", "Address": "someLocation"]
print(adressDicts[1]) // ["Zip": 456, "City": "DEF", "Address": "someLocation"]
}
or, without an intermediate step ...
if let adressDicts = profile["Addresses"] as? [[String: Any]] {
print(adressDicts[0]) // ["Zip": 123, "City": "ABC", "Address": "someLocation"]
print(adressDicts[1]) // ["Zip": 456, "City": "DEF", "Address": "someLocation"]
}
But this is just a small lesson in attempted typed conversion (-> don't do this).