Reputation: 507
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!
Upvotes: 2
Views: 1741
Reputation: 40963
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?
Upvotes: 4
Reputation: 41236
To start with, iOS doesn't use NSPoint, so that would be a loss. My best guess for something like this would be to fall back to using objCType, which is how it would be handled in objective-C. Unfortunately, you don't have access to @encode from swift, so you wind up having to hardcode the possibilities:
switch String(CString: value.objCType, encoding: NSUTF8StringEncoding) {
case "{CGPoint=dd}": // handle CGPoint here
case "{CGRect={CGPoint=dd}{CGSize=dd}}": // handle CGRect here
}
Upvotes: 2