2012-04-25 22 views
7

MyClass.h:Come si accede alla variabile dichiarata in un'estensione di classe?

@interface MyClass : NSObject 
@end 

MyClass.m:

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

Poi più tardi nella lldb:

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

Così come si fa accedere a quella variabile nella debugger?

Utilizzo di xcode 4.3.2

Grazie!

risposta

-1

Se è necessario accedere a name dall'esterno dei metodi MyClass, è necessario definire i metodi per accedervi. Potresti semplicemente scrivere i metodi chiamati (NSString*) name e - (void) setName:(NSString*) newName, ma è più semplice definire le proprietà e sintetizzarle.

In MyClass.h, si definisce una proprietà. Per le stringhe, di solito farli copy:

@interface MyClass : NSObject 

@property (copy) NSString* name; 

@end 

In MyClass.m, si utilizza ancora la vostra dichiarazione di interfaccia, con l'ivar:

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

Tuttavia, è anche bisogno di sintetizzare la tua nuova proprietà. Questo crea metodi per recuperare e impostare nome:

@implementation MyClass 

@synthesize name = name; 

@end 

Per convenzione, è comune a mettere un carattere di sottolineatura all'inizio o alla fine del Ivar, in modo nell'interfaccia si avrebbe NSString *_name;, e nel implementazione si avrebbe @synthesize name = _name. Questo aiuta ad evitare di usare accidentalmente l'ivar quando intendi la proprietà.

è ora possibile accedere il tuo nome proprietà:

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

proprietà Objective-C sono una potente funzione della lingua, ma hanno alcune stranezze si deve imparare. Prova una ricerca sul web per una combinazione di "oggettivo C", "proprietà" e "sintetizza".

Se si verificano ancora errori del compilatore, modificare la domanda con la parte del codice a cui si accede name.

+0

L'OP chiede come accedere alla variabile nel debugger. Non come farlo compilare. Ho lo stesso problema. Questa risposta non è utile. – rrrus

6

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

+0

bene, questo funziona, ma è sicuramente una brutta soluzione. – rrrus

+0

@rrrus si, ma usa il runtime, funzionerà anche con proprietà '@ dynamic', es. dati di base .. –

+0

Non funziona se quello che stai cercando è un ivar e non una proprietà. – AriX

0

L'unico modo per accedere in modo pulito queste variabili istanza direttamente è tramite il runtime Objective-C, che fornisce la funzione utile object_getInstanceVariable. Il valore viene passato per riferimento e potrebbe essere di molti tipi diversi, quindi non è molto utile dal debugger. Ma la tua domanda mi ha ispirato a trovare una soluzione.

Ho scritto una categoria su NSObject che consente di analizzare le variabili di istanza dal debugger, senza preoccuparsi degli effetti collaterali di accesso. Dopo aver aggiunto la categoria al progetto, si può fare questo:

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

Ecco il codice:

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 

Si noti che la categoria verrà disabilitata automaticamente durante la compilazione per il rilascio (grazie al debu g macro).

+0

se vuoi rendere questa una categoria di NSObject ... ok ma sembra un po 'pesante per guardare un paio di valori nel debugger ... –

+0

Haha, hai ragione di nuovo. Quando ho commentato la tua risposta, non pensavo che sarebbe finita abbastanza pesante. Ho sbagliato dappertutto! Ma è una risposta precisa alla domanda "come accedi direttamente a una variabile di istanza" e penso che sarà utile quando farò lo sviluppo di Cocoa, dato che spesso scrivo accessor che popolano una variabile di istanza se non è impostata ancora. – AriX

+1

La prima versione era di 4 righe, ma mi sono un po 'trascinata quando ho notato che non funzionava con i tipi non-Objective-C ... – AriX

Problemi correlati