4

Supposing we have:

id value = [self valueForKey:@"frame"];
BOOL valueIsCGRect = ???;

How can I decide? Should I cast id to something?

Geri Borbás
  • 15,810
  • 18
  • 109
  • 172

3 Answers3

7

The returned value will be of type NSValue for scalar types, which provides the method objCType, which returns the encoded type of the wrapped scalar type. You can use @encode() to get the encoding for an arbitrary type, and then compare the objCType.

if(strcmp([value objCType], @encode(CGRect)) == 0)
{
   // It's a CGRect
}
JustSid
  • 25,168
  • 7
  • 79
  • 97
  • @Kevin Whoops, good catch, thanks! Though, after reading your answer, I'm not sure if my answer is even remotely correct... I think I totally misunderstood the question there. – JustSid Aug 23 '13 at 15:35
  • I think you answered the question he asked, I just answered the problem and underlying misunderstanding. – Kevin Aug 23 '13 at 15:36
  • That really seems the answer, though I cannot send objcType message to an id. Should I cast it before to... ...something? – Geri Borbás Aug 23 '13 at 15:39
  • @Geri You sure can, you just have to type it correctly, unlike me (it's `objCType`, not `objcType`, sorry). But, if you know that you will access the `frame` property and not arbitrary properties, you also know that it returns a `CGRect`, in which case @Kevin's answer is the correct one. – JustSid Aug 23 '13 at 15:41
  • 1
    @JustSid Shouldn't you first verify that `value` is actually an `NSValue` object? – rmaddy Aug 23 '13 at 15:42
  • @rmaddy Yup, I just assumed that its already verified that there is an `NSValue` object at hand. – JustSid Aug 23 '13 at 15:45
  • Yap. I missed it, just found objCType in NSValue documentation. It spells with capital "C" by the way. Thanks, answer just superfine. – Geri Borbás Aug 23 '13 at 15:46
4

CGRect is a struct, not an Objective-C object, so if you have an id, you don't have a CGRect.

What you probably have is an NSValue wrapping a CGRect. You can get the CGRect out using [value CGRectValue].

frame should certainly return a (wrapped) CGRect, but if you really need to check and make sure, you can use JustSid's answer.

Community
  • 1
  • 1
Kevin
  • 53,822
  • 15
  • 101
  • 132
  • It shows a NSRect actually, when I simply NSLog(@"%@", value), not NSValue. – Geri Borbás Aug 23 '13 at 15:36
  • @Geri That's because the returned value is actually of type `NSConcreteValue`, a subclass of `NSValue`. It still is an `NSValue`. – JustSid Aug 23 '13 at 15:37
  • One question still remains - Once you know you have an `NSValue`, how do you know if the `NSValue` contains a `CGRect` or some other value? I think you need to look at the `NSValue objCType` but I don't know what it will equal for a `CGRect`. – rmaddy Aug 23 '13 at 15:41
2

With a bit more context and some typecasting:

id value = [self valueForKeyPath:keyPath];

//Core Graphics types.
if ([value isKindOfClass:[NSValue class]])
{
    //CGRect.
    if(strcmp([(NSValue*)value objCType], @encode(CGRect)) == 0)
    {
        //Get actual CGRect value.
        CGRect rectValue;
        [(NSValue*)value getValue:&rectValue];

        NSLog(@"%@", NSStringFromCGRect(rectValue));
    }

    //CGPoint.
    if(strcmp([(NSValue*)value objCType], @encode(CGPoint)) == 0)
    {
        //Get actual CGPoint value.
        CGPoint pointValue;
        [(NSValue*)value getValue:&pointValue];

        NSLog(@"%@", NSStringFromCGPoint(pointValue));
    }
}
titaniumdecoy
  • 18,900
  • 17
  • 96
  • 133
Geri Borbás
  • 15,810
  • 18
  • 109
  • 172