Search code examples
iosswiftnsvalue

How to know the type of the object boxed in NSValue with Swift?


I have an NSValue object that can "box" an instance of an unknown type (CGPoint, CGRect, etc.) and I need to determine this type in runtime. How would I do it in Swift?

I tried to do something like this:

if ((value as Any) is CGPoint) {}
else if (((value as Any) is CGRect)) {}
...

When value is a NSValue object containing a CGPoint, it does not get into the if clause. Then I when I printed value it gives me NSPoint: {150, 150} which I assume is why it never gets in the clause.

Any ideas why this happens and how to solve it?

Thanks a lot!


Solution

  • Ah, NSValue, you so crazy. Even though NSRect etc aren't supposed to be a thing on iOS, if you put a CGRect inside an NSValue, internally it displays it has an NSRect inside it.

    Anyway, while they serve similar purposes I don't think you can use Any to convert an NSValue to or from a CGPoint or CGRect. You have to call value.CGRectValue() etc. But to your point, you need to know which it is. Which also isn't easy, but you can do this:

    let type = String.fromCString(val.objCType) ?? ""
    if type.hasPrefix("{CGRect") {
        let rect = val.CGRectValue()
    }
    else if type.hasPrefix("{CGPoint") {
        let point = val.CGPointValue()
    } //etc...
    

    But another question would be, do you really need to use NSValue? It's kind of an Obj-C specific workaround. Is it being given to you by something you can’t change or might you be better off using Any (or even better, generics) instead?