Objective c 目标C反射-提取属性名

Objective c 目标C反射-提取属性名,objective-c,reflection,nsstring,Objective C,Reflection,Nsstring,我试图找出一种方法,提取给定对象的属性名称,不是所有属性的名称,而是一个特定的名称。为此,我在类中实现了此方法: -(NSString *)keyForProperty:(NSObject *)theProperty{ unsigned int propertyCount = 0; objc_property_t * properties = class_copyPropertyList([self class], &propertyCount); for (unsigned int

我试图找出一种方法,提取给定对象的属性名称,不是所有属性的名称,而是一个特定的名称。为此,我在类中实现了此方法:

-(NSString *)keyForProperty:(NSObject *)theProperty{
unsigned int propertyCount = 0;
objc_property_t * properties = class_copyPropertyList([self class], &propertyCount);

for (unsigned int i = 0; i < propertyCount; ++i) {
    objc_property_t property = properties[i];

    NSString *name=[NSString stringWithUTF8String:property_getName(property)];

    NSObject * propertyValue=[self valueForKey:name];
    if(propertyValue==theProperty){
        free(properties);
        return name;

    }
}
free(properties);

return nil;

}
问题是,在我的类A中,我有两个属性p1和p2都是NSString,而在A的init方法中,我将@“”分配给这两个属性。问题是p1和p2然后指向相同的内存位置,因此当我这样做时:

 NSString *name=[foo keyForProperty:foo.p1];

我对他们两个都得到了相同的结果。 在为两个属性分配@“”时,您知道如何防止这种情况发生吗? 你认为有更好的方法来实现这一点吗?这些要求是给定的和目标的:

 A* foo=[[A alloc]init];
对于A类,我必须能够得到一个特定的属性名

多谢各位

解释我为什么需要这个:

我有一个UIViewController子类TextEditingVC,它所做的就是接收和编辑对象,编辑属性名,编辑过程由TextEditingVC实例自动管理,我所要做的就是:

A *foo;

//lets edit property p
NSString *key=[foo keyForProperty:foo.p];
TextEditingVC *theVC=[TextEditingVC alloc]initWithEditableObject:foo withEditionKey:key];
//present theVC in some way
此TextEditingVC应该能够编辑任何对象的NSString属性。这个想法是使TextEditingVC尽可能通用,因为在我的应用程序中,我必须编辑各种类的属性NSString

当然,我可以简单地使用:

NSString *key=@"p";
而不是:

NSString * key=[foo keyForProperty:foo.p];

但是在这种情况下,字符串将在我的代码中硬编码,为了良好的编程实践,我想避免使用它,或者我在这种特殊情况下尝试避免硬编码字符串是错误的吗?

您可以以不同的方式初始化两个属性(p1=@“v1”,p2=@“v2”)

您可以以不同的方式初始化两个属性(p1=@“v1”,p2=@“v2”)

我不知道如何实现您想要的功能。但是,您可能会使使用硬编码密钥名的访问更加安全。例如,您可能会制作一个宏,如:

#define CHECKED_PROPERTY(obj, prop) ((void)((obj).prop), @#prop)
此宏使用逗号运算符扩展为表达式。首先计算
obj.prop
子表达式,但放弃其结果。这只是为了让编译器验证表达式,因此如果
prop
不是
obj
的有效属性,它会抱怨。第二个子表达式stringify使用
#
预处理器运算符设置
prop
参数。它在其前面加上
@
前缀,以将字符串文字转换为Objective-C
NSString
文字

并像这样使用它:

NSString* key = CHECKED_PROPERTY(foo, p);
这扩展到:

NSString* key = ((void)((foo).p), @"p");
这将计算
foo.p
,但忽略结果,并具有将
键设置为
@“p”
的效果


然后,如果您重构并将
p
重命名为
x
,重构引擎(如果它真的很聪明)会发现它需要对上述内容进行处理,或者至少编译器会抱怨重构没有成功。(如果您将
p
重命名为
x
并将
q
重命名为
p
,则会出现这种情况。)

我不知道如何实现您想要的目标。但是,您可以使用硬编码的键名进行访问。例如,您可以制作如下宏:

#define CHECKED_PROPERTY(obj, prop) ((void)((obj).prop), @#prop)
此宏使用逗号运算符扩展为表达式。首先计算
obj.prop
子表达式,但放弃其结果。这只是为了让编译器验证表达式,因此如果
prop
不是
obj
的有效属性,它会抱怨。第二个子表达式stringify使用
#
预处理器运算符设置
prop
参数。它在其前面加上
@
前缀,以将字符串文字转换为Objective-C
NSString
文字

并像这样使用它:

NSString* key = CHECKED_PROPERTY(foo, p);
这扩展到:

NSString* key = ((void)((foo).p), @"p");
这将计算
foo.p
,但忽略结果,并具有将
键设置为
@“p”
的效果


然后,如果您重构并将
p
重命名为
x
,重构引擎(如果它真的很聪明)会发现它需要对上述内容进行处理,或者至少编译器会抱怨重构没有成功。(如果您将
p
重命名为
x
并将
q
重命名为
p
,则会出现此问题。)

我还不明白您试图实现的目标。为什么要调用
NSString*name=[foo-keyForProperty:foo.p1]
,而不是
name=@“p1”"
?-你永远不能期望一个对象的所有属性都有不同的值。-也许你可以给出一个更好的例子来说明如何使用该方法。这听起来非常脆弱。对
valueForKey:
返回的值进行指针比较不是一个好主意。我同意你的观点,它是脆弱的,这就是我为什么要尝试的原因面对一些问题…我在寻找更好的解决方案,有什么想法吗?我已经更新了帖子,补充了一些我为什么需要的解释this@Mppl:但是在
key=[foo-keyForProperty:foo.p]
中,您还硬编码了属性名称(在
foo.p
中为“p”)。-我仍然不明白为什么这比
[TextEditingVC alloc]initWithEditableObject:foo withEditionKey:@“p”]
。事实上,我认为我不会这样做:假设明天我想将属性名从p更改为x,我只需在Xcode中使用重构工具,并在类防御中将p更改为x,无需在代码中查找@“p”字符串以@“x”替换,您对某些内容的硬编码是正确的,但我的方法更容易实现,不是吗?我还不明白您想要实现什么。为什么要调用
NSString*name=[foo-keyForProperty:foo.p1]
而不是
name=@“p1”
?-你永远不能期望一个对象的所有属性都有不同的值。-也许你可以给出一个更好的例子,说明如何使用该方法。这听起来非常脆弱。对从