如何在运行时检查属性是否声明为@dynamic



我正在开发一个字典的动态实现,该字典还支持使用@dynamic关键字声明的属性(类似于NSManagedObject)。

我能在运行时判断一个特定的选择器是否是用@dynamic声明的吗?这只是设计时工具的编译器把戏,在运行时丢失了吗?或者有什么方法可以检查一下吗?

+ (BOOL) resolveInstanceMethod:(SEL)sel
{
    NSString *method = NSStringFromSelector(sel);
    // ideally I could also check here if the selector is @dynamic
    if ([method hasPrefix:@"set"] && [method rangeOfString:@":"].location == method.length -1) {
        class_addMethod([self class], sel, (IMP) dynamicSet, "v@:@");
        return YES;
    }
    else if ([method hasPrefix:@"get"] && [method rangeOfString:@":"].location == method.length -1) {
        class_addMethod([self class], sel, (IMP) dynamicGet, "v@:@");
        return YES;
    }
    BOOL value = [super resolveInstanceMethod:sel];
    return value;
}

此外,我的类子类化了NSDictionary,但当为现有方法调用[super-resolveInstanceMethod:sel]时,它仍然返回false?

如果您知道属性的名称,您可以使用一些运行时函数来调查它是否是动态属性,如下函数所示。请确保导入<objc/runtime.h>

BOOL isClassPropertyDynamic(Class theClass, NSString *propertyName)
{
    BOOL isDynamic = NO;
    objc_property_t property = class_getProperty(theClass, [propertyName UTF8String]);
    char *dynamicAttributeValue = property_copyAttributeValue(property, "D");
    if (dynamicAttributeValue != NULL) {
        isDynamic = YES;
        free(dynamicAttributeValue);
    }
    return isDynamic;
}

然而,从选择器名称转到属性并不总是容易的,因为getter和setter名称都可以在声明时自定义。通常,这只针对布尔属性的getter,但从技术上讲,任何人都可以打破这种约定。

按照惯例,如果选择器以"set"开头,后跟一个大写字母,并在末尾包含一个":",则属性名称将是删除"set"one_answers":"并使第一个字母小写后产生的字符串。如果选择器以"is"开头,后面跟着一个大写字母,并且没有参数,那么与之对应的属性名称将是删除"is"并使第一个字母小写后产生的字符串。没有参数且不以"is"开头且使用大写字母的选择器的属性名称和选择器名称通常相同。

再说一遍,这只是惯例,会被某个地方的人打破。因此,你必须决定确定选择器是否对应于动态属性是否真的有价值(就像borrrden一样,我怀疑它是否真的相关,但我不熟悉你的要求)。

您还可以遵循rob mayoff在评论中的出色建议,即"迭代所有属性(使用class_copyPropertyList)并检查每个属性的G和s(属性)",以在选择器和属性之间建立映射。

最新更新