2012-04-25 9 views
7

MyClass.h:¿Cómo se accede a la variable declarada en una extensión de clase?

@interface MyClass : NSObject 
@end 

MyClass.m:

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

Luego, más tarde en LLDB:

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

Entonces, ¿cómo acceder a esa variable en el depurador?

Usando xcode 4.3.2

Gracias!

Respuesta

-1

Si necesita acceder a name desde fuera de los métodos MyClass, debe definir los métodos para acceder a él. Simplemente podría escribir métodos llamados (NSString*) name y - (void) setName:(NSString*) newName, pero es más fácil definir propiedades y sintetizarlas.

En MyClass.h, defina una propiedad. Para las cadenas, por lo general los hacen copy:

@interface MyClass : NSObject 

@property (copy) NSString* name; 

@end 

En MyClass.m, todavía se utiliza su declaración de interfaz, con el Ivar:

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

Sin embargo, también es necesario para sintetizar su nueva propiedad. Esto crea métodos para la recuperación y configuración nombre:

@implementation MyClass 

@synthesize name = name; 

@end 

Como convención, es común poner un guión al principio o al final de la Ivar, por lo que en la interfaz que tendría NSString *_name;, y en el implementación tendría @synthesize name = _name. Esto ayuda a evitar el uso accidental del ivar cuando se refería a la propiedad.

ahora puede acceder a su nombre propiedad:

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

propiedades de Objective-C son una potente característica de la lengua, pero tienen algunas peculiaridades que usted debe aprender. Intente buscar en la web alguna combinación de "objetivo-C", "propiedades" y "sintetizar".

Si aún tiene errores de compilación, edite su pregunta con la parte de su código donde tiene acceso al name.

+0

OP pregunta cómo acceder a la variable en el depurador. No cómo hacer para compilar. Tengo el mismo problema. Esta respuesta no es útil. – rrrus

6

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

+0

bueno, esto funciona, pero seguro que es una solución fea. – rrrus

+0

@rrrus, sí, pero usa el tiempo de ejecución, también funcionará para las propiedades '@ dynamic', es decir. datos básicos .. –

+0

No funciona si lo que estás buscando es un ivar y no una propiedad. – AriX

0

La única forma de acceder a limpiamente estas variables de instancia directamente es a través del tiempo de ejecución de Objective-C, que proporciona la función útil object_getInstanceVariable. El valor se pasa por referencia, y podría ser de muchos tipos diferentes, por lo que no es muy útil desde el depurador. Pero su pregunta me inspiró a encontrar una solución.

Escribí una categoría en NSObject que le permite introspectar las variables de instancia del depurador, sin preocuparse por los efectos secundarios del accesorio. Después de la adición de la categoría a su proyecto, usted puede hacer esto:

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

Aquí está el código:

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's try that.", ivarName, underscoredIvarName); 

     return [self valueOfInstanceVariable:underscoredIvarName]; 

    // If there's 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 

Tenga en cuenta que la categoría se desactivará automáticamente al compilar para su lanzamiento (gracias a debu g macro).

+0

si quiere hacer de esto una categoría de NSObject ... bien, pero parece un poco difícil de ver un par de valores en el depurador ... –

+0

Jaja, tienes razón de nuevo. Cuando comencé su respuesta, no pensé que terminaría siendo tan pesado. Estoy equivocado en todo el lugar! Pero es una respuesta precisa a la pregunta "¿cómo accedes directamente a una variable de instancia?", Y creo que será útil cuando estoy desarrollando Cocoa, ya que a menudo escribo accesos que completan una variable de instancia si no está configurada todavía. – AriX

+1

La primera versión tenía 4 líneas, pero me llevé un poco de emoción cuando noté que no funcionaba para tipos que no eran de Objective-C ... – AriX

Cuestiones relacionadas