Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving property list of a class in iOS

I am trying to retrieve a list of all the properties that my class or any of its subclasses define. The following code snippet is the code that I have been using, and it has worked properly all the way until the recent iOS8 beta 4.

if(!dictionary) {
    dictionary = [NSMutableDictionary dictionary];

    // Get all properties we have until we hit CBLNestedModel
    while(klass != [CBLNestedModel class]) {
        unsigned count;
        objc_property_t* properties = class_copyPropertyList(klass, &count);
        for (unsigned i = 0; i < count; i++) {
            objc_property_t property = properties[i];

            const char* propertyNameC = property_getName(property);
            NSString* propertyName = [NSString stringWithUTF8String:propertyNameC];
            const char* propertyAttrC = property_getAttributes(property);
            NSString* propertyAttrS = [NSString stringWithUTF8String:propertyAttrC];
            NSArray* propertyAttr = [propertyAttrS componentsSeparatedByString:@","];
            NSLog(@"%@ has property %@", NSStringFromClass(klass), propertyName);

            dictionary[propertyName] = propertyAttr;
        }
        free(properties);
        klass = [klass superclass];
    }

    propertyDictionary[klassString] = dictionary;
}

CBLNestedModel derives from NSObject. Basically, I want all properties that any subclass of CBLNestedModel declares, or its subclasses. The issue that I'm facing is that now, this code is returning extraneous properties that are not defined in my subclasses.. propertyNames are coming back with @"superclass", @"description", @"debugDescription", @"hash" for certain classes, even though I have never defined these properties anywhere in my subclasses.

A weird thing is that these extraneous properties are not returned for all subclasses of CBLNestedModel, but only for certain subclasses. However, they will reliably be returned for those subclasses on every run of my app.

Any idea why this is happening now?

like image 855
rvijay007 Avatar asked Jul 21 '14 19:07

rvijay007


2 Answers

Do your CBLNestedModel subclasses adhere to any protocols? I was previously seeing a similar issue with an object I had and could not figure out why hash, description, superclass, and debugDescription were showing up and I finally figured it out. Here was what I had:

@interface FOOObject : NSObject<NSCopying, FOOOtherProtocol>

Looks fine, it was a direct subclass of NSObject. In fact I had other objects for testing this, one with properties and one without.

@interface FOOObjectWithProperties : NSObject

@property NSString *someProperty;

@end

and

@interface FOOObjectWithoutProperties : NSObject
@end

During the tests FOOObjectWithProperties and FOOObjectWithoutProperties both did not have the four aforementioned NSObject properties included, but the original FOOObject DID.

So what was the difference? Well looking at NSCopying it didn't appear to add any properties so I looked at FOOOtherProtocol, some protocol I had implemented and it didn't have any properties declared either.

HOWEVER

Look at the declaration of FOOOtherProtocol:

@protocol FOOOtherProtocol<NSObject>

THERE IT IS. The objective-c runtime stuff does NOT include superclass properties in what is returned it will however include properties declared in protocol extensions (protocols that force adherence to other protocols).

Notice anything about hash, description, superclass, and debugDescription?

Look at where they are declared in the NSObject protocol declaration

Remove the forced NSObject protocol adherence from your subclasses' protocol(s) (since they are subclasses of NSObject anyway that already adheres to it) and you should see those properties go away.

like image 130
Dean Kelly Avatar answered Sep 28 '22 08:09

Dean Kelly


Looks like on iOS 8 those 4 methods are now declared as read-only properties in NSObject.

More info here.

like image 27
André Morujão Avatar answered Sep 28 '22 07:09

André Morujão