Search code examples
dictionaryswiftdowncast

Downcast element when reading from Dictionary in Swift


I'm trying to access an element a dictionary element and downcast it to a type other than AnyObject but keep getting the same compiler error: Could not find an overload for 'subscript' that accepts the supplied arguments.

I know I can just do this using two if statements like so:

if let x = dict["key"] {
    if let y = x as? String {
        // ...
    }
}

But I feel there has to be a more elegant solution than this. The format that makes the most sense to me is:

if let x = dict["key"] as? String {
    // ...
}

But this just results in the error, mentioned above. I've tried dozens of variations of this, but none of it seems to make any difference. Is this something that just can't be done in Swift?


Solution

  • The reason your desired formulation isn't working is that you're trying to unwrap two Optionals with a single as?. There are two Optionals because both the subscripting of your dictionary and the attempted cast to String return optional values. There isn't a way to do it in one if statement that will be runtime-safe, but there is a way:

    if let x = dict["key"]! as? String {
        println(x)
    }
    

    The problem is that if dict["key"] ends up being nil, the forced unwrapping will crash your app. Better to do it this way (you can skip the first if), even if it is an extra step:

    let x: AnyObject? = dict["key"]
    if let y = x as? String {
        println(y)
    }
    

    The extra step is just the cost of working with a Dictionary<String, AnyObject> - if you can get your dictionary type more specific, you won't have to do it any more.