我正在开发一个字典的动态实现,该字典也支持使用@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?
答案 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的优秀建议,以构建选择器和属性之间的映射。