获取属性名称作为string

我需要一种方式来传递一个属性,并获得分配给它的名称。 有什么build议么?

@property (nonatomic, retain) MyObject *crazyObject; NSString *str = SOME_WAY_TO_GET_PROPERTY_NAME(crazyObject); // Above method should return @"crazyObject" 

你可以试试这个:

 unsigned int propertyCount = 0; objc_property_t * properties = class_copyPropertyList([self class], &propertyCount); NSMutableArray * propertyNames = [NSMutableArray array]; for (unsigned int i = 0; i < propertyCount; ++i) { objc_property_t property = properties[i]; const char * name = property_getName(property); [propertyNames addObject:[NSString stringWithUTF8String:name]]; } free(properties); NSLog(@"Names: %@", propertyNames); 

就像这个一样简单……扩大Chuck已经提到的内容:

 #ifndef STR_PROP #define STR_PROP( prop ) NSStringFromSelector(@selector(prop)) #endif 

然后,您可以像这样使用它:

 NSString *strProp = STR_PROP(myProperty); 

背景

请记住, 引用苹果的属性实际上是“一个声明类的访问器方法的语法简写”。 实际上,@property声明本身并不起作用。 您的@synthesize语句将@synthesize翻译为两个方法的等价物:

 - (void)setCrazyObject:(MyObject *)something; - (MyObject *)crazyObject; 

使用哪一个取决于self.crazyObject的上下文。 ( @synthesize也创build了一个匹配的实例variables,如果你自己没有做的话)。所有这一切的分支是你不能真正用一种方法翻译属性。

build议的解决scheme

您可以使用Apple已经提供的内容:

 NSString *foo = NSStringFromSelector(@selector(myClassProperty)); 

或者做一些自定义的:

假设self.crazyObject在代码运行时真的转化为[self crazyObject][self setCrazyObject:foo] ,那么可能需要两个方法:

 - (NSString *)setterStringForProperty:(SEL)prop; - (NSString *)getterStringForProperty:(SEL)prop; 

然后您可能需要至less2个伴随方法,例如:

 - (SEL)setterForPropertyName:(NSString *)propString; - (SEL)getterForPropertyName:(NSString *)propString; 

在这些方法中,可以使用基础函数 NSStringFromSelectorNSSelectorFromString在SEL和NSString之间来回转换。 使用任何你喜欢的string操作在setterstring(setCrazyObject)和属性名称(crazyObject)之间来回转换。

一个完整的解决scheme很难在不知道具体用例的情况下提供,但是希望这可以为尝试完成类似任务的任何人提供更多的线索。 把这种方法与奥斯卡的回答结合起来,甚至可能会有一些有用的东西成为可能。

这是一个函数,返回一个伊娃的名字,所以它基本上不仅返回属性,而且还返回该类的任何伊娃。 我还没有find直接获得财产的方法,所以我使用了伊娃的技巧。

 #import <objc/objc.h> /// ----- - (NSString *)nameOfIvar:(id)ivarPtr { NSString *name = nil; uint32_t ivarCount; Ivar *ivars = class_copyIvarList([self class], &ivarCount); if(ivars) { for(uint32_t i=0; i<ivarCount; i++) { Ivar ivar = ivars[i]; id pointer = object_getIvar(self, ivar); if(pointer == ivarPtr) { name = [NSString stringWithUTF8String:ivar_getName(ivar)]; break; } } free(ivars); } return name; } 

search和debugging后,我find了解决scheme…

新增了#import <objc/runtime.h>

方法object_getIvar(id obj,Ivar ivar)发送错误的访问和应用程序崩溃。 我修改了一些代码,它工作得很好:

 +(NSString*)stringWithProperty:(id)property withClass:(id)controller { NSString *name = nil; uint32_t ivarCount; Ivar *ivars = class_copyIvarList([controller class], &ivarCount); if(ivars) { for(uint32_t i=0; i<ivarCount; i++) { Ivar ivar = ivars[i]; name = [NSString stringWithUTF8String:ivar_getName(ivar)]; if ([controller valueForKey:name] == property) { break; } } free(ivars); } return name; } 

修改解决scheme,当你的对象已经分配时,它会起作用,否则返回nil: –

 NSString * NSStringFromProperty(NSObject* property, NSObject* class) { unsigned int propertyCount = 0; objc_property_t * properties = class_copyPropertyList([class class], &propertyCount); NSString *name = nil; for (unsigned int i = 0; i < propertyCount; ++i) { name = [NSString stringWithUTF8String:property_getName(properties[i])]; NSObject *object = [class valueForKey:name]; if (object != nil && object == property) { break; } else { name = nil; } } free(properties); return name; } 

从Get属性名称作为string,不使用运行时参考库 ,只需定义:

 #define propertyKeyPath(property) (@""#property) #define propertyKeyPathLastComponent(property) [[(@""#property) componentsSeparatedByString:@"."] lastObject] 

然后你可以做这样的事情:

  NSLog(@"%@", propertyKeyPathLastComponent(appleStore.storeLocation.street)); //result: street 

您可以在Gist中检查我的方法,获取具有自动完成和编译时检查的属性的string。

如何使用:

获取一个的属性名称:

 @interface AnyClass : NSObject @property (strong) NSData *data; @end // == My approach == // C string for a class PropertyNameForClass(AnyClass, data); // ==> "data" // NSString for a class PropertyStringForClass(AnyClass, data); // ==> @"data" // Bad approach (no autocompletion; no compile-time check): NSString *propertyName = @"data"; 

获取协议的属性名称:

 @protocol AnyProtocol @property (strong) NSDate *date; @end // C string for a protocol PropertyNameForProtocol(AnyProtocol, date); // ==> "date" // NSString for a protocol PropertyStringForProtocol(AnyProtocol, date); // ==> @"date" 

您可以使用

 NSString *str = NSStringFromSelector(@selector(crazyObject)); 

这种方法的好处是:

  1. Xcode会为你自动填充单词crazyObject
  2. 稍后,您将把属性名称从crazyObjectmyCrazyObject ,Xcode将添加一条警告,指出"unrecognized selector!" – 很好的debugging。

我经常使用这个方法,我甚至创build了一个函数,它允许写更less的字母:

 NSString * __nonnull sfs(SEL __nonnull theSelector) { if (!theSelector) { abort(); } return NSStringFromSelector(theSelector); } 

现在你的最终解决scheme可以像这样:

 NSString *str = sfs(@selector(crazyObject));