25

プロパティを渡し、それに割り当てられた名前を取得する方法が必要です。助言がありますか?

@property (nonatomic, retain) MyObject *crazyObject;

NSString *str = SOME_WAY_TO_GET_PROPERTY_NAME(crazyObject);
// Above method should return @"crazyObject"
4

10 に答える 10

24

これを試すことができます:

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);
于 2011-07-07T19:18:12.170 に答える
20

それはこれと同じくらい簡単です...チャックがすでに述べたことを拡張します:

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

次に、次のように使用します。

NSString *strProp = STR_PROP(myProperty);
于 2012-09-27T13:57:13.657 に答える
15

バックグラウンド

プロパティは、Apple の言葉を借りれば、「クラスのアクセサ メソッドを宣言するための構文上の省略形」であることに注意してください。実際、@property 宣言自体は機能しません。あなたの@synthesizeステートメントは、@propertyを 2 つのメソッドに相当するものに変換します。

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

どちらが使用されるかは、self.crazyObject を取り巻くコンテキストによって異なります。(@synthesize自分で行っていない場合は、一致するインスタンス変数も作成します。) このすべての派生物は、1 つのメソッドでプロパティとの間で実際に変換できないことです。

提案された解決策

Apple がすでに提供しているものを使用できます。

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

または、何かカスタムを行います。

self.crazyObject が実際に[self crazyObject]または[self setCrazyObject:foo]コードが実行されるまでに変換されることを考えると、次のような 2 つのメソッドが必要になるでしょう。

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

次に、次のような少なくとも 2 つのコンパニオン メソッドが必要になる場合があります。

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

これらのメソッド内で、Foundation 関数 NSStringFromSelectorを使用NSSelectorFromStringして、SEL と NSString の間で相互に変換できます。任意の文字列操作を使用して、セッター文字列 (setCrazyObject) とプロパティ名 (crazyObject) の間で相互に変換します。

正確なユースケースを知らずに完全なソリューションを提供することは困難ですが、同様のことを達成しようとしている人にとって、これがいくつかの手がかりになることを願っています. このアプローチをオスカーの答えと組み合わせることで、いくつかの有用なことが可能になるかもしれません.

于 2011-10-20T04:16:35.223 に答える
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;
}
于 2011-07-07T19:30:03.850 に答える
2

使用できます

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));
于 2016-02-05T23:07:40.227 に答える
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;
}
于 2014-04-23T06:37:41.623 に答える
1

Get property name as stringから、ランタイム参照ライブラリを使用せずに、次を定義するだけです:

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

そして、次のようなことができます:

 NSLog(@"%@", propertyKeyPathLastComponent(appleStore.storeLocation.street)); //result: street
于 2015-06-17T09:40:40.773 に答える