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?
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.
Looks like on iOS 8 those 4 methods are now declared as read-only properties in NSObject.
More info here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With