Search code examples
swifttypesoption-typedowncastanyobject

Swift AnyObject Conversion


I created some test code to show the problem I am having.

This compiles fine in a playground, however, when I try to put it into a project, Xcode gives the following warning: Treating a forced downcast to 'String' as optional will never produce 'nil' on line 30. I am given two suggestions to fix the problem:

  1. Use 'as?' to perform a conditional downcast to 'String', which makes absolutely no sense. However, it does compile without warnings/errors, which seems strange because it is assigning an optional value to a non-optional type of String.

    Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.

    From the Swift language guide.

    Unless it thinks I might want to assign nil if the conversion fails (therefore removing the dictionary entry), this makes no sense. Especially because I am sure it will succeed because I literally just checked to see if it was a String.

  2. Add parentheses around the cast to silence this warning, which seems pointless, but does silence the warning. This seems like a strange thing to do, but then again, it may just be a poor way of confirming that you really want to do what you are trying to do.


Which option is right, or neither? What is causing this warning?


Solution

  • The correct solution is to use optional binding instead of the forced unwrap operator !. Actually you can incorporate the check value != nil into the switch statement:

    for (key, value) in dict {
        switch value {
        case let s as String:
            newDict[key] = s
        case let i as Int:
            newDict[key] = String(i)
        case let b as Bool:
            newDict[key] = b ? "1" : "0"
        case let v?:   // value is not `nil`
            newDict[key] = String(v)
        default:       // value is `nil`
            break
        }
    }