如果在@dynamic中声明属性,如何在运行时检查

时间:2013-08-12 03:44:47

标签: ios objective-c

我正在开发一个字典的动态实现,该字典也支持使用@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?

1 个答案:

答案 0 :(得分:3)

如果您知道属性的名称,则可以使用某些运行时函数来调查它是否为动态属性,如以下函数所示。请务必导入<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”和“:”并生成第一个字母的字符串小写。 如果选择器以“is”开头,后跟大写字母并且没有参数,那么与之对应的属性名称将是删除“is”并使第一个字母为小写的字符串。选择器没有参数且不以“是”开头,大写字母通常具有属性名称和选择器名称相同。

同样,这只是惯例,并会被某个人打破。所以,你必须决定确定选择器是否与动态属性相对应是否真的很有价值(比如borrrden我怀疑它是否真的相关但我不熟悉你的要求)。

你也可以按照你在“迭代所有属性(使用class_copyPropertyList)并检查每个属性的G和S(属性)”的评论中关注rob mayoff的优秀建议,以构建选择器和属性之间的映射。