How do you access a variable declared in a class extension?

MyClass.h:

@interface MyClass : NSObject @end 

MyClass.m:

 // Define a private variable in a class extension @interface MyClass () { NSString *name; } @end 

Then later in lldb:

 (lldb) po myClassInstance->name error: 'MyClass' does not have a member named 'name' error: 1 errors parsing expression 

So how do you access this variable in the debugger?

Using xcode 4.3.2

Thanks!

+7
source share
3 answers

(lldb) po [myClassInstance valueForKey:@"name"]

+6
source

The only way to directly access these instance variables directly is through the Objective-C runtime, which provides a useful object_getInstanceVariable function. The value is passed by reference and can be of many different types, so it is not very useful from the debugger. But your question prompted me to come up with a solution.

I wrote a category in NSObject that allows you to insert instance variables from the debugger without worrying about the side effects of access. After adding a category to your project, you can do this:

 (lldb) po [self valueOfInstanceVariable:@"_name"] IMG_4078.PNG 

Here is the code:

NSObject + IvarIntrospection.h

 #if DEBUG #import <Foundation/Foundation.h> @interface NSObject (IvarIntrospection) - (id)valueOfInstanceVariable:(NSString *)ivarName; @end #endif 

NSObject + IvarIntrospection.m

 #if DEBUG #import "NSObject+IvarIntrospection.h" #import <objc/runtime.h> @implementation NSObject (IvarIntrospection) - (id)valueOfInstanceVariable:(NSString *)ivarName { // Get the value of the instance variable // Use a union in order to convert the value to a float or double (see http://en.wikipedia.org/wiki/Type_punning) union { void *value; float f; double d; } ivar; Ivar ivarInfo = object_getInstanceVariable(self, [ivarName UTF8String], &ivar.value); // If the instance variable doesn't exist, try adding an underscore if (!ivarInfo && ![ivarName hasPrefix:@"_"]) { NSString *underscoredIvarName = [@"_" stringByAppendingString:ivarName]; NSLog(@"Instance variable '%@' does not exist. Perhaps you meant '%@?' Let try that.", ivarName, underscoredIvarName); return [self valueOfInstanceVariable:underscoredIvarName]; // If there already an underscore, error } else if (!ivarInfo) { NSLog(@"Instance variable '%@' does not exist.", ivarName); return nil; } // Figure out what type the instance variable is and return a sensible representation const char *type = ivar_getTypeEncoding(ivarInfo); switch (type[0]) { case 'c': return [NSNumber numberWithChar:(char)ivar.value]; case 'i': return [NSNumber numberWithInt:(int)ivar.value]; case 's': return [NSNumber numberWithShort:(short)ivar.value]; case 'l': return [NSNumber numberWithLong:(long)ivar.value]; case 'q': return [NSNumber numberWithLongLong:(long long)ivar.value]; case 'C': return [NSNumber numberWithUnsignedChar:(unsigned char)ivar.value]; case 'I': return [NSNumber numberWithUnsignedInt:(unsigned int)ivar.value]; case 'S': return [NSNumber numberWithUnsignedShort:(unsigned short)ivar.value]; case 'L': return [NSNumber numberWithUnsignedLong:(unsigned long)ivar.value]; case 'Q': return [NSNumber numberWithUnsignedLongLong:(unsigned long long)ivar.value]; case 'f': return [NSNumber numberWithFloat:ivar.f]; case 'd': return [NSNumber numberWithDouble:ivar.d]; case '*': return [NSString stringWithUTF8String:(const char *)ivar.value]; case '@': case '#': return (id)ivar.value; case ':': return NSStringFromSelector((SEL)ivar.value); default: return [NSValue valueWithBytes:&ivar.value objCType:type]; } } @end #endif 

Please note that the category will be automatically disabled when compiling for release (thanks to the debug macro).

0
source

If you need to access name from outside MyClass methods, you need to define methods to access it. You could just write methods called (NSString*) name and - (void) setName:(NSString*) newName , but it's easier to define properties and synthesize them.

In MyClass.h, you define a property. For strings, you usually copy them:

 @interface MyClass : NSObject @property (copy) NSString* name; @end 

In MyClass.m, you are still using the interface declaration, with ivar:

 @interface MyClass () { NSString *name; } @end 

However, you also need to synthesize a new property. This creates methods for extracting and setting the name:

 @implementation MyClass @synthesize name = name; @end 

As a legend, the underscore is usually underlined at the beginning or end of ivar, so in the interface you will have NSString *_name; , and in the implementation you will have @synthesize name = _name . This helps to avoid the accidental use of ivar when you mean the property.

Now you can access the name property:

 MyClass me = [[[MyClass alloc] init] autorelease]; [me setName:@"My name"]; NSLog(@"Name = %@", [me name]); 

Objective-C properties are a powerful feature of the language, but they have some quirks that you should learn. Try searching the net for some combination of objective-C, properties, and synthesize.

If you still have errors in the compiler, edit your question using the part of your code where you get access to name .

-one
source

All Articles