获取属性名称作为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;
在这些方法中,可以使用基础函数 NSStringFromSelector
和NSSelectorFromString
在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));
这种方法的好处是:
- Xcode会为你自动填充单词
crazyObject
。 - 稍后,您将把属性名称从
crazyObject
为myCrazyObject
,Xcode将添加一条警告,指出"unrecognized selector!"
– 很好的debugging。
我经常使用这个方法,我甚至创build了一个函数,它允许写更less的字母:
NSString * __nonnull sfs(SEL __nonnull theSelector) { if (!theSelector) { abort(); } return NSStringFromSelector(theSelector); }
现在你的最终解决scheme可以像这样:
NSString *str = sfs(@selector(crazyObject));