3

我正在研究字典的动态实现,该字典还支持使用@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?

4

1 回答 1

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 名称都可以在声明时自定义。通常,这仅适用于布尔属性的吸气剂,但从技术上讲,任何人都可以打破这种约定。

按照惯例,如果选择器以“set”开头,后跟一个大写字母并在末尾包含一个“:”,则属性名称将是删除“set”和“:”并将第一个字母变为小写的字符串。如果选择器以“is”开头,后跟一个大写字母并且没有参数,则对应的属性名称将是删除“is”并将第一个字母变为小写的字符串。没有参数并且不以“is”和大写字母开头的选择器通常具有相同的属性名称和选择器名称。

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

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

于 2013-08-12T04:25:49.080 回答