views:

2458

answers:

3

How can I get a list (in the form of an NSArray or NSDictionary) of a given object attributes in Objective-C?

Imagine the following scenario: I have defined a parent class which just extends NSObject, that holds an NSString, a BOOL and an NSData object as attributes. Then I have several classes which extend this parent class, adding a lot of different attributes each.

Is there any way I could implement an instance method on the parent class that goes through the whole object and returns, say, an NSArray of each of the (child) class attributes as NSStrings that are not on the parent class, so I can later use these NSString for KVC?

A: 

The word "attributes" is a little fuzzy. Do you mean instance variables, properties, methods that look like accessors?

The answer to all three is "yes, but it's not very easy." The Objective-C runtime API includes functions to get the ivar list, method list or property list for a class (e.g., class_copyPropertyList()), and then a corresponding function for each type to get the name of an item in the list (e.g., property_getName()).

All in all, it can be kind of a lot of work to get it right, or at least a lot more than most people would want to do for what usually amounts to a really trivial feature.

Alternatively, you could just write a Ruby/Python script that just reads a header file and looks for whatever you'd consider "attributes" for the class.

Chuck
Hi chuck, thanks for your response. What I was refering to with 'attributes' was indeed to a class properties. I already managed to accomplish what I wanted by making use of the Obj-C Runtime Library. Using a script to parse the header file wouldn't have worked for what I needed on runtime.
boliva
+10  A: 

I just managed to get the answer myself. By using the Obj-C Runtime Library, I had access to the properties the way I wanted:

- (void)myMethod {
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for(i = 0; i < outCount; i++) {
     objc_property_t property = properties[i];
     const char *propName = property_getName(property);
     if(propName) {
      const char *propType = getPropertyType(property);
      NSString *propertyName = [NSString stringWithCString:propName];
      NSString *propertyType = [NSString stringWithCString:propType];
      ...
     }
    }
    free(properties);
}

This required me to make a 'getPropertyType' C function, which is mainly taken from an Apple code sample (can't remember right now the exact source):

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T') {
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "@";
}
boliva
A: 

When I tried with iOS 3.2, the getPropertyType function doesn't work well with the property description. I found an example from iOS documentation: "Objective-C Runtime Programming Guide: Declared Properties".

Here is a revised code for property listing in iOS 3.2:

#import <objc/runtime.h>
#import <Foundation/Foundation.h>
...
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([UITouch class], &outCount);
for(i = 0; i < outCount; i++) {
    objc_property_t property = properties[i];
    fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}
free(properties);
Chatchavan