我需要一种传递属性并获取分配给它的名称的方法。有什么建议吗?
@property (nonatomic, retain) MyObject *crazyObject;
NSString *str = SOME_WAY_TO_GET_PROPERTY_NAME(crazyObject);
// Above method should return @"crazyObject"
答案 0 :(得分:23)
你可以试试这个:
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);
答案 1 :(得分:20)
就像这一样简单......扩展了查克已经提到的内容:
#ifndef STR_PROP
#define STR_PROP( prop ) NSStringFromSelector(@selector(prop))
#endif
然后你就这样使用它:
NSString *strProp = STR_PROP(myProperty);
答案 2 :(得分:14)
<强>背景强>
请记住,对于quote Apple来说,属性实际上只是“声明类的访问器方法的语法简写”。实际上,@ property的声明本身并不起作用。您的@synthesize
语句会将@property
转换为相当于两种方法的内容:
- (void)setCrazyObject:(MyObject *)something;
- (MyObject *)crazyObject;
使用哪一个取决于你的self.crazyObject周围的上下文。 (@synthesize
如果你自己不这样做,也会创建一个匹配的实例变量。)所有这一切的分支是你无法用一种方法真正转换为属性。
提议的解决方案
您可以使用Apple提供的功能:
NSString *foo = NSStringFromSelector(@selector(myClassProperty));
或做一些自定义的事情:
鉴于self.crazyObject在代码运行时确实转换为[self crazyObject]
或[self setCrazyObject:foo]
,您可能需要两种方法,例如:
- (NSString *)setterStringForProperty:(SEL)prop;
- (NSString *)getterStringForProperty:(SEL)prop;
您可能需要至少2种配套方法,例如:
- (SEL)setterForPropertyName:(NSString *)propString;
- (SEL)getterForPropertyName:(NSString *)propString;
在这些方法中,您可以使用Foundation functions NSStringFromSelector
和NSSelectorFromString
在SEL和NSString之间来回转换。使用您喜欢的任何字符串操作在您的setter字符串(setCrazyObject)和您的属性名称(crazyObject)之间来回转换。
在不知道具体用例的情况下很难提供完整的解决方案,但希望这为任何试图完成类似工作的人提供了更多线索。将这种方法与奥斯卡的答案相结合,甚至可能会有一些有用的东西成为可能。
答案 3 :(得分:4)
这是一个返回ivar名称的函数,所以基本上它不仅返回属性,还返回类的任何ivar。我没有找到直接获得财产的方法所以我使用了ivar技巧。
#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;
}
答案 4 :(得分:3)
搜索和调试后,我找到了解决方案......
添加了#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;
}
答案 5 :(得分:2)
修改解决方案,它在您的对象已经分配时有效,否则返回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;
}
答案 6 :(得分:1)
从Get property name as string, without using the runtime reference library开始,只需定义:
#define propertyKeyPath(property) (@""#property)
#define propertyKeyPathLastComponent(property) [[(@""#property) componentsSeparatedByString:@"."] lastObject]
然后你可以这样做:
NSLog(@"%@", propertyKeyPathLastComponent(appleStore.storeLocation.street)); //result: street
答案 7 :(得分:1)
您可以在Gist检查我的方法,以获取具有自动完成和编译时检查的属性的字符串。
获取类的属性名称:
@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"
答案 8 :(得分:1)
您可以使用
```{r}
library(dygraphs)
lungDeaths <- cbind(mdeaths, fdeaths)
res <- lapply(1:2, function(i) dygraph(lungDeaths[, i]))
htmltools::tagList(res)
```
这种方法的好处在于:
NSString *str = NSStringFromSelector(@selector(crazyObject));
。crazyObject
更改为crazyObject
,Xcode会添加警告myCrazyObject
- 非常适合调试。我经常使用这种方法,甚至创建了一个函数,它允许写更少的字母:
"unrecognized selector!"
现在您的最终解决方案可能如下所示:
NSString * __nonnull sfs(SEL __nonnull theSelector)
{
if (!theSelector)
{
abort();
}
return NSStringFromSelector(theSelector);
}
答案 9 :(得分:0)
非常规的,hacky的,丑陋的,迟到的,但是...就像它的名字一样具有强大的魅力,就像魅力一样:
#define SOME_WAY_TO_GET_PROPERTY_NAME(p) p == p ? [[[[[[[NSString alloc] initWithCString:#p encoding:NSUTF8StringEncoding] componentsSeparatedByString:@"."] lastObject] componentsSeparatedByString:@" "] lastObject] stringByReplacingOccurrencesOfString:@"]" withString:@""] : @""
样品用量:
NSLog(SOME_WAY_TO_GET_PROPERTY_NAME(self.customer.surname)); // surname
NSLog(SOME_WAY_TO_GET_PROPERTY_NAME([[self customer] birthDate])); // birthDate
...