获取属性名称作为字符串

问题描述 投票:25回答:10

我需要一种方法来传递一个属性并获得分配给它的名字。有什么建议么?

@property (nonatomic, retain) MyObject *crazyObject;

NSString *str = SOME_WAY_TO_GET_PROPERTY_NAME(crazyObject);
// Above method should return @"crazyObject"
objective-c introspection objective-c-runtime declared-property
10个回答
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);

0
投票

标新立异,哈克的,丑陋的,晚了,但是......作为强名称,因为它会和工作就像一个魅力:

#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
...

20
投票

它是如此简单......在什么查克已经提到的扩大:

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

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

NSString *strProp = STR_PROP(myProperty);

14
投票

背景

请记住,性能真的只是,到quote Apple,“一个语法速记声明一个类的访问方法。”事实上,通过本身,@property声明甚至不工作。你@synthesize语句转换的@property到的两种方法是等效的:

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

使用哪一个取决于围绕你的self.crazyObject上下文。 (@synthesize也创造了一个匹配的实例变量,如果你没有自己做。)所有这一切的支脉的是,你不能真正转化为从一个单一的方法的属性。

建议的解决方案

您可以使用苹果公司已经提供:

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

或者做一些自定义的:

鉴于self.crazyObject你的代码运行的时间真的转换要么[self crazyObject][self setCrazyObject:foo],ou'll大概需要两个方法,如:

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

那么你可能想至少2种同伴的方法,如:

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

在这些方法,您可以使用Foundation functions NSStringFromSelectorNSSelectorFromString来回转换SEL和的NSString之间。使用任何字符串操作你喜欢来回转换您的二传手字符串(setCrazyObject)和你的属性名称(crazyObject)之间。

完整的解决方案是很难提供不知道确切的使用情况,但希望这为任何人试图完成类似的东西了一些端倪。甚至有可能是通过组合与奥斯卡的答案这一做法成为可能一些有用的东西。


4
投票

这里是返回伊娃的名称的函数,所以基本上它不仅返回属性,但任何类伊娃。我还没有找到一种方式来获得直接,所以我用伊娃招财产。

#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;
}

3
投票

搜索和调试后,我发现我的解决方案...

新增#import <objc/runtime.h>

方法object_getIvar(ID OBJ,伊瓦尔伊瓦尔)发送坏的接入和应用程序崩溃。我修改一些代码,它的伟大工作:

+(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;
}

2
投票

修改的解决方案,它的工作原理,当你的对象是已分配,否则返回零: -

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;
}

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

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"

1
投票

您可以使用

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

这种方法的好处是:

  1. Xcode中会自动填充字crazyObject你。
  2. 如果以后你会在属性名从crazyObject改为myCrazyObject,Xcode中会增加一个警告说"unrecognized selector!" - 用于调试的不错。

我用这个方法所以很多时候,我甚至创造了一个功能,它允许少写字母:

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

现在,您的最终解决方案可以是这样的:

NSString *str = sfs(@selector(crazyObject));
© www.soinside.com 2019 - 2024. All rights reserved.