在iOS中检索类的属性列表

6

我想要获取我的类或其任何子类定义的所有属性列表。以下代码片段是我一直在使用的代码,一直到最近的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派生自NSObject。基本上,我想要任何CBLNestedModel子类或其子类声明的所有属性。我面临的问题是,现在,这段代码返回了不属于我的子类中定义的多余属性。对于某些类,propertyNames会返回 @"superclass",@"description",@"debugDescription",@"hash",即使我从未在我的子类中定义过这些属性。

奇怪的是,这些多余属性并不会为CBLNestedModel的所有子类返回,而只会为某些子类返回。但是,它们将可靠地在每次运行我的应用程序时返回这些子类。

你有什么想法为什么现在会发生这种情况吗?


这里也有同样的问题。非常奇怪,因为superclassdescriptiondebugDescriptionhash不是属性,而是由NSObject实现的NSObjectProtocol方法。第一个问题:这是一个错误吗?第二个问题:我们应该创建一个雷达吗? - Martin
1
是的,这一定是个bug。在iOS7中,这段代码运行得非常完美。我们一定要通过bugreport.apple.com提交bug报告。希望更多人报告这个问题,这将促使他们在下一个更新中修复它。 - rvijay007
@Martin @rvijay007 这不是一个错误,它们现在是iOS 8中的属性。问题是为什么它们只出现在某些子类中。 我也遇到了同样的问题,但我有一个XC测试用例,其中一个对象是NSObject的直接子类,在调用其属性方法时不显示这些内容。但我有另一个对象,另一个直接子类,在应用程序的正常操作期间确实返回hashdescriptionsuperclassdebugDescription。你能否分享更多关于你的子类的信息,以帮助发现问题?或者有关报告的更新? - Dean Kelly
我也遇到了同样的问题,而且仅限于某些类。我不确定为什么只有某些类会出现这种情况。你解决了吗? - odyth
@odyth,我可能已经搞定了,并在下面发表了我的答案。 - Dean Kelly
2个回答

9

你的CBLNestedModel子类是否遵守任何协议?我之前也遇到过一个类似的问题,但无法弄清楚为什么hashdescriptionsuperclassdebugDescription会出现在我的对象中,最终我才搞清楚。这是我之前的代码:

@interface FOOObject : NSObject<NSCopying, FOOOtherProtocol>

看起来很好,它是NSObject的直接子类。实际上,我有其他用于测试的对象,一个带属性,一个不带属性。

@interface FOOObjectWithProperties : NSObject

@property NSString *someProperty;

@end

并且

@interface FOOObjectWithoutProperties : NSObject
@end

在测试过程中,FOOObjectWithPropertiesFOOObjectWithoutProperties没有包含上述四个NSObject属性,但原始的FOOObject有。

那么区别在哪里呢?好吧,看一下NSCopying,它似乎没有添加任何属性,于是我查看了一下FOOOtherProtocol,这是我实现的某个协议,它也没有声明任何属性。

然而

请看FOOOtherProtocol的声明:

@protocol FOOOtherProtocol<NSObject>

这里有一个提示。Objective-C运行时相关的东西不会包括超类属性,但是它会包括在协议扩展中声明的属性(强制遵循其他协议的协议)。

注意一下hashdescriptionsuperclassdebugDescription的声明位置?

看看它们在NSObject协议声明中的位置。

从你的子类协议中删除强制的NSObject协议遵从(因为它们已经是NSObject的子类了),你应该会发现这些属性消失了。


我认为你说得很到点子上了。我的代码中出问题的那些类最终都遵循 NSObject 协议,这是一个不错的发现。 - odyth
@odyth 谢谢!我花了一些时间挖掘,哈哈,但现在我知道了,感觉就像知道了一个魔术的秘密;有点苦涩的满足感。 - Dean Kelly

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接