2013-08-06 8 views
5

Quando dichiaro un @property in una superclasse senza dichiarare ivars, sottoclassi e cerco di implementare getter usando le superclasse ivar (_propertyName) nella sottoclasse, xcode richiama un errore che indica Use of undeclared identifier '_propertyName'.Dichiarare ivars nella superclasse o @synthesize nella sottoclasse?

Qual è la soluzione conforme alle migliori pratiche di programmazione?

Dovrei @synthesize propertyName = _propertyName nel @implementation della sottoclasse o

@interface SuperClass : AnotherClass 
{ 
    Type *_propertyName; 
} 

@property Type *propertyName; 

@end 

EDIT:
faccio capire la "sintesi" automatico dei metodi di accesso alle proprieta e la creazione di 'underbar Ivars' dal compilatore.
L'ivar è accessibile dall'implementazione di SuperClass senza alcun @synthesize o dichiarazione di ivars nell'interfaccia o nella sezione di implementazione.

ulteriore chiarimento del mio caso: Disclaimer: Contenuto rubati blocco di codice da Alfie Hanssen

@interface SuperViewController : UIViewController 
@property (nonatomic, strong) UITableView * tableView; // ivar _tableView is automatically @synthesized 
@end 

#import "SuperViewController.h" 

@interface SubViewController : SuperViewController 
// Empty 
@end 

@implementation SubViewController 

- (void)viewDidLoad 
{ 
    NSLog(@"tableView: %@", self.tableView); // this is perfectly OK 
} 

// ************* This causes problem ************** 
- (UITableView *) tableView { 
    if (!_tableView) { // Xcode error: Use of undeclared identifier '_propertyName' 
     _tableView = [[SubclassOfUITableView alloc] init]; 
    } 
    return _tableView; 
} 
// ************************************************ 


@end 
+0

Questo è strano: in Objective C gli ivar sono protetti per impostazione predefinita, quindi le sottoclassi dovrebbero essere in grado di accedervi come se fossero le proprie. Come si accede a '_propertyName' per ottenere quell'errore? – dasblinkenlight

+4

Se la vostra proprietà è '@property Tipo * _propertyName;' allora penserei che ivar sarebbe '__propertyName'. (Due trattini bassi) Perché la sottoclasse necessita di un accesso diretto a Ivar? – BergQuester

+0

FYI, non c'è più bisogno di proprietà '@ synthesize'; basta dichiararli nel file di intestazione e la sintesi viene eseguita automaticamente da Xcode/il compilatore. – davidf2281

risposta

7

Se si desidera utilizzare un ivar sia nella superclasse che nella sottoclasse, è necessario dichiararlo nell'interfaccia della superclasse, poiché è l'unico file incluso in entrambe le implementazioni. Altrimenti, stai solo cercando di indovinare cosa potrebbe esserci nell'implementazione della superclasse e xcode non giocherà.

Quanto sopra è vero se esiste una proprietà che usa quel ivar oppure no.

Ora, se si dispone di una proprietà nella superclasse e si scrive nella realizzazione sottoclasse:

@synthesize propertyName = _propertyName 

Stai solo dicendo che si sta abbandonando qualunque implementazione di quella proprietà era nella superclasse e si desidera il setter e il getter standard generati da xcode, che lavorano su un ivar chiamato _propertyname. Forse la superclasse funziona allo stesso modo, forse no.

0

Questo dovrebbe funzionare bene. self.tableView e _tableView dovrebbero essere entrambi accessibili da SubViewController.

@interface SuperViewController : UIViewController 
@property (nonatomic, strong) UITableView * tableView; // ivar _tableView is automatically @synthesized 
@end 

#import "SuperViewController.h" 

@interface SubViewController : SuperViewController 
// Empty 
@end 

@implementation SubViewController 

- (void)viewDidLoad 
{ 
    NSLog(@"tableView: %@", self.tableView); 
} 

@end 

Edit: Va bene ora capisco che sei domanda migliore. Dai un'occhiata a questo question. Sembra un duplicato e sembra che risponda alla tua domanda. Cioè sembra che dovrai definire esplicitamente la variabile di istanza.

+0

OK, cosa succede se ho aggiunto questo metodo all'implementazione SubViewController: - (UITableView *) tableView { if (! _tableView) { _tableView = [[SubclassOfUITableView alloc] init]; } return _tableView; } – user2626382

+0

"ivar _tableView viene automaticamente \ @sinteso" Come lo sai? Si presume che non ci sia \ @synthesize nel file m né l'implementazione personalizzata del getter o setter. Come puoi saperlo? – Nicolas

+0

Non è un duplicato di quella domanda poiché i casi sono opposti. Voglio l'ivar, non devo sintetizzarlo, poiché la superclasse implementa solo setter e la proprietà è 'readwrite' - l'ivar è facilmente accessibile dall'implementazione della superclasse. – user2626382

0

Apparentemente la sintesi automatica dell'avorio non funziona in questo caso. Il seguente codice non riesce con l'errore del compilatore "uso dell'identificatore non dichiarato _x", ma solo per l'uso in JFNBclass. Decommentare la dichiarazione di ivar e l'errore del compilatore scompare. La sintesi predefinita non sembra creare _x che sia visibile alla classe ereditaria.

JFNAclass.h

#import <Foundation/Foundation.h> 

@interface JFNAclass : NSObject { 
    // NSNumber *_x; 
} 

@property NSNumber *x; 
- (NSNumber *) xTest; 

@end 

JFNAclass.m

#import "JFNAclass.h" 

@implementation JFNAclass 

- (NSNumber *) xTest 
{ 
    return _x; 
} 

@end 

JFNBclass.h

#import <Foundation/Foundation.h> 
#import "JFNAclass.h" 

@interface JFNBclass : JFNAclass 

- (void) printIt; 
- (void) setIt; 

@end 

JFNBclass.m

#import "JFNBclass.h" 

@implementation JFNBclass 

- (void) setIt 
{ 
    _x = [[NSNumber alloc] initWithInt:2]; 
} 

- (void) printIt 
{ 
    NSLog(@"_x is %@", _x); 
} 

@end 
+1

[Qual è la visibilità delle variabili di istanza sintetizzate?] (Http://stackoverflow.com/q/8510464) –

+0

Non ho eseguito quel test ... ... i risultati sono completamente coerenti con la risposta SO riferimento. Quelle sorpresa! Così ho svalutato questa risposta. – Fred

+0

È bello da parte tua che ti sia preso il tempo di scrivere questo, ho scritto codice quasi identico. ma se leggete attentamente, ho persino dichiarato questa soluzione nel titolo. – user2626382

0

Ivars creati da @synthesize sono @private. (Questo è vero sia per le esplicite @synthesize dichiarazioni e sintesi automatica.)

La classe SuperViewController ha un Ivar _tableView, ma è così @private sottoclasse non può usarlo. Se hai bisogno di un ivar che le sottoclassi possano usare, dovrai dichiararlo esplicitamente e renderlo diverso da @private. (Si consiglia inoltre di utilizzare @synthesize tableView=_tableView in modo che la proprietà utilizzi l'ivar dichiarato.)

0

Non avrei accesso a ivar. Si desidera ignorare il getter, quindi è sufficiente chiamare lo super.

+0

Probabilmente avrei dovuto fornire più codice. Analogamente al mio caso '[super tableView]' restituire '(UITableView *)' ('alloc'ed e' init'ed) - non 'nil' - quindi il getter della sottoclasse non restituirebbe (probabilmente)' SubclassOfUITableView'. – user2626382

+0

Ancora, ** Non accetterei affatto ivar. ** Se entrambi i getter sono pigri, ma restituiscono una classe diversa di 'UITableView', quindi il metodo' - (Class) tableViewClass' lo sovrascrivono. C'è sempre una bella soluzione. – Tricertops