7

Let's say I have a piece of code like this:

let x: Int? = 10  
let y: Any = x

Now I want to cast y to Int?:

let z = y as Int? // Error: Cannot downcast from 'Any' to a more optional type 'Int?'

Is this just not possible or is there another way?

Nikita Kukushkin
  • 14,648
  • 4
  • 37
  • 45

5 Answers5

8

For Swift 2.0, you can use the following:

let x: Int? = 10
let y: Any = x
let z = Mirror(reflecting: y).descendant("Some") as? Int

Or as a function:

func castToOptional<T>(x: Any) -> T? {
    return Mirror(reflecting: x).descendant("Some") as? T
}
let x: Int? = 10
let y: Any = x
let z: Int? = castToOptional(y)

Or you can do this if you don't like Reflection:

func castToOptional<T>(x: Any) -> T {
    return x as! T
}
let x: Int? = 10
let y: Any = x
let z: Int? = castToOptional(y)
Sandy Chapman
  • 11,133
  • 3
  • 58
  • 67
  • I think this method fails to cast `Any` to a typed optional in Swift 3 / xcode 8. – SimplGy Jun 30 '16 at 00:36
  • Ah hah! lowercase "s" in `some`. Reading release notes is useful sometimes! For swift 3, use `let z = Mirror(reflecting: y).descendant("some") as? Int` – SimplGy Jun 30 '16 at 00:38
  • The `Mirror(reflecting: x).descendant(…) ` approach doesn't work in Swift 3 (`Mirror(reflecting: x).children.count` is `0`), but the `return x as! T` does!  For some strange reason, trying to do `(myAnyVar as! SCNRenderingAPI?)` gives me a compile-time error `error: cannot downcast from 'Any' to a more optional type 'SCNRenderingAPI?'`, but doing the same cast inside a function as you have it works great.  Cheers!   |   Suggested edit: _“Or you can do this if you don't like Reflection:”_ → _“Or you can do this in Swift 3 or if you don't like Reflection:”_ – Slipp D. Thompson May 26 '17 at 22:18
0

You can do this to get an optional out on Any

func unwrap(any:Any) -> Any? {
    let mi:MirrorType = reflect(any)
    if mi.disposition != .Optional {
        return any
    }
    if mi.count == 0 { return nil } // Optional.None
    let (name,some) = mi[0]
    return some.value
}

So in your case,

let z = unwrap(y) as? Int

Reference : How to unwrap an optional value from Any type?

Community
  • 1
  • 1
Mustafa
  • 5,307
  • 1
  • 20
  • 19
0
func castAsOptionalInt(value: Any)->Int? {
    let mirror = Mirror(reflecting:value)
    if mirror.subjectType == Optional<Int>.self {
        let ret = mirror.children.first?.1
        return ret as? Int
    } else {
        return nil
    }
}

let x: Int? = 10
let y: Any = x
let z = castAsOptionalInt(y) // 10
let a: Double? = 10
let b: Any = a
let c = castAsOptionalInt(b) // nil
user3441734
  • 16,722
  • 2
  • 40
  • 59
0

how about this solution, I made a generic version of previous answer.

fileprivate func unwrap<T>(value: Any)
  -> (unwraped:T?, isOriginalType:Bool) {

  let mirror = Mirror(reflecting: value)
  let isOrgType = mirror.subjectType == Optional<T>.self
  if mirror.displayStyle != .optional {
    return (value as? T, isOrgType)
  }
  guard let firstChild = mirror.children.first else {
    return (nil, isOrgType)
  }
  return (firstChild.value as? T, isOrgType)
}

let value: [Int]? = [0]
let value2: [Int]? = nil

let anyValue: Any = value
let anyValue2: Any = value2

let unwrappedResult:([Int]?, Bool)
  = unwrap(value: anyValue)    // ({[0]}, .1 true)
let unwrappedResult2:([Int]?, Bool)
  = unwrap(value: anyValue2)  // (nil, .1 true)
let unwrappedResult3:([UInt]?, Bool)
  = unwrap(value: anyValue)  // (nil, .1 false)
let unwrappedResult4:([NSNumber]?, Bool)
  = unwrap(value: anyValue)  ({[0]}, .1 false)

The following is code on Playground.

enter image description here

Keith
  • 111
  • 1
  • 6
0

In case anyone's looking for a plug-and-play Dictionary solution, something like this:

extension Dictionary where Value == Any {
    func typedValue<T>(forKey key: Key) -> T? {
        if let anyValue: Any = self[key] {
            return (anyValue as! T)
        }
        return nil
    }

    func optionalTypedValue<T>(forKey key: Key) -> T?? {
        return self.typedValue(forKey: key)
    }
}
xtravar
  • 1,321
  • 11
  • 24