Question

I have an object in objective-c at runtime, from which I only know the KVC key and I need to detect the return value type (e.g. I need to know if its an NSArray or NSMutableArray) of this property, how can I do that?

Was it helpful?

Solution

You're talking about runtime property introspection, which happens to be something that Objective-C is very good at.

In the case you describe, I'm assuming you have a class like this:

@interface MyClass
{
    NSArray * stuff;
}
@property (retain) NSArray * stuff;
@end

Which gets encoded in XML something like this:

<class>
    <name>MyClass</name>
    <key>stuff</key>
</class>

From this information, you want to recreate the class and also give it an appropriate value for stuff.

Here's how it might look:

#import <objc/runtime.h>

// ...

Class objectClass;       // read from XML (equal to MyClass)
NSString * accessorKey;  // read from XML (equals @"stuff")

objc_property_t theProperty =
    class_getProperty(objectClass, accessorKey.UTF8String);

const char * propertyAttrs = property_getAttributes(theProperty);
// at this point, propertyAttrs is equal to: T@"NSArray",&,Vstuff
// thanks to Jason Coco for providing the correct string

// ... code to assign the property based on this information

Apple's documentation (linked above) has all of the dirty details about what you can expect to see in propertyAttrs.

OTHER TIPS

Cheap answer: use the NSObject+Properties source here.

It implements the same methodology described above.

The preferred way is to use the methods defined in the NSObject Protocol.

Specifically, to determine if something is either an instance of a class or of a subclass of that class, you use -isKindOfClass:. To determine if something is an instance of a particular class, and only that class (ie: not a subclass), use -isMemberOfClass:

So, for your case, you'd want to do something like this:

// Using -isKindOfClass since NSMutableArray subclasses should probably
// be handled by the NSMutableArray code, not the NSArray code
if ([anObject isKindOfClass:NSMutableArray.class]) {
    // Stuff for NSMutableArray here
} else if ([anObject isKindOfClass:NSArray.class]) {
    // Stuff for NSArray here

    // If you know for certain that anObject can only be
    // an NSArray or NSMutableArray, you could of course
    // just make this an else statement.
}

This is really a comment addressing an issue raised by Greg Maletic in response to answer provided by e.James 21APR09.

Agreed that Objective-C could use a better implementation for getting these attributes. Below is a method I quickly threw together to retrieve attributes of a single object property:

- (NSArray*) attributesOfProp:(NSString*)propName ofObj:(id)obj{

    objc_property_t prop = class_getProperty(obj.class, propName.UTF8String);
    if (!prop) {
       // doesn't exist for object
       return nil;
    }
    const char * propAttr = property_getAttributes(prop);
    NSString *propString = [NSString stringWithUTF8String:propAttr];
    NSArray *attrArray = [propString componentsSeparatedByString:@","];
    return attrArray;
}

Partial list of attribute keys:

  • R Read-only
  • C Copy of last value assigned
  • & Reference to last value assigned
  • N Nonatomic property
  • W Weak reference

Full list at Apple

You can use isKindOfClass message

if([something isKindOfClass:NSArray.class])
     [somethingElse action];

If you know that the property is defined :

        id vfk = [object valueForKey:propertyName];
        Class vfkClass = vfk.class;

And compare with isKindOfClass, isSubClass, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top