19

Say I have my class

@interface Person : NSObject { NSString *name; }

I need to get the name of NSString's within my class

Person *person = [[Person alloc] init];
NSLog(@"Name of variable %s\n", _NameofVariable_(person->name));

Thanks for the answers, here's the solution I came up from the replies

//returns nil if property is not found
-(NSString *)propertyName:(id)property {  
    unsigned int numIvars = 0;
    NSString *key=nil;
    Ivar * ivars = class_copyIvarList([self class], &numIvars);
    for(int i = 0; i < numIvars; i++) {
        Ivar thisIvar = ivars[i];
        if ((object_getIvar(self, thisIvar) == property)) {
            key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
            break;
        }
    } 
    free(ivars);
    return key;
}  
hacksignal
  • 633
  • 1
  • 7
  • 11

5 Answers5

37

As easy as

#define VariableName(arg) (@""#arg)

Then you do:

NSObject *obj;
NSString *str = VariableName(obj);
NSLog(@"STR %@", str);//obj
Andrey Chernukha
  • 21,488
  • 17
  • 97
  • 161
  • 1
    Has anyone tried this? Try VariableName(here_s_a_random_string_that_s_not_a_var) This isn't a way to get a property or ivar to return it's name. This is just a way to save you from typing @"" around some text - and instead you're using VariableName(). Or am I missing something? – mahboudz Jan 24 '15 at 10:39
  • Note if you pass a macro it will return the macro name not the object that macro is set to. – Albert Renshaw Oct 22 '17 at 02:54
  • 1
    How do this in Swift for NSObject? – ChikabuZ Oct 27 '17 at 09:32
4

You can get the names of a class's instance variables with the Objective-C runtime API function class_copyIvarList. However, this is rather involved, rarely done and almost never the best way to accomplish something. If you have a more specific goal in mind than mere curiosity, it might be a good idea to ask about how to accomplish it in Objective-C.

Also, incidentally, person.name doesn't specify an instance variable in Objective-C — it's a property call. The instance variable would be person->name.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • I didn't know you could access instance variables that way. Will likely never use it, but good to know. – Brandon Bodnar Mar 20 '10 at 21:45
  • @Brandon you can do that because Objective-C objects are really just structs. :) – Dave DeLong Mar 20 '10 at 23:16
  • @Brandon, you do need to be careful when using the `person->name` idiom, because whereas `person.name` takes advantage of nil object behavior and would simply return `nil` if `person` is `nil`, `person->name` will likely crash if `person` is `nil`, just like good ol' C or C++. – fullofsquirrels Apr 13 '16 at 20:34
2

You might use preprocessor stringification and a bit of string twiddling:

NSUInteger lastIndexAfter(NSUInteger start, NSString *sub, NSString *str) {
    NSRange found = [str rangeOfString:sub options:NSBackwardsSearch];
    if(found.location != NSNotFound) {
        NSUInteger newStart = NSMaxRange(found);
        if(newStart > start)
            return newStart;
    }
    return start;
}

NSString *lastMember(NSString *fullName) {
    if(!fullName) return nil;

    NSUInteger start = 0;
    start = lastIndexAfter(start, @".", fullName);
    start = lastIndexAfter(start, @"->", fullName);

    return [fullName substringFromIndex: start];
}

#define NSStringify(v) (@#v)
#define _NameofVariable_(v) lastMember(NSStringify(v))
Chris Johnsen
  • 214,407
  • 26
  • 209
  • 186
0

If the person object is exposed as a property of the class, you can use objc_msgSend to get the value.

So, if you could access person using

[object person]

You could also do

objc_msgSend(object, "person")

For more details on message sending, including how to pass arguments to methods, see the Objective-C Runtime Programming Guide section on Messaging

Robert Christie
  • 20,177
  • 8
  • 42
  • 37
0

The following works as a macro:

#define STRINGIZE(x) #x
Zorayr
  • 23,770
  • 8
  • 136
  • 129