Proprietà vs variabile di istanza

Sto cercando di capire in che modo alcune persone usano le strategie per distinguere le varianti di istanza vs proprietà. Un modello comune è il seguente:

@interface MyClass : NSObject { NSString *_myVar; } @property (nonatomic, retain) NSString *myVar; @end @implementation MyClass @synthesize myVar = _myVar; 

Ora, ho pensato che l’intera premessa dietro questa strategia è che si possa facilmente distinguere la differenza tra un ivar e una proprietà. Quindi, se voglio usare la gestione della memoria ereditata da una proprietà sintetizzata, userei qualcosa come:

 myVar = @"Foo"; 

L’altro modo sarebbe fare riferimento a se stesso. [Ivar / proprietà qui].

Il problema con l’utilizzo della strategia @synthesize myVar = _myVar, è che ho pensato di scrivere codice come:

 myVar = some_other_object; // doesn't work. 

Il compilatore si lamenta che myVar non è dichiarato. Perché è così?

Grazie.

Le proprietà sono solo setter e getter per ivars e dovrebbero (quasi) essere sempre utilizzate al posto dell’accesso diretto.

 @interface APerson : NSObject { // NSString *_name; // necessary for legacy runtime } @property(readwrite) NSString *name; @end @implementation APerson @synthesize name; // use name = _name for legacy runtime @end 

@synthesize crea in questo caso quei due metodi (non accurati al 100%):

 - (NSString *)name { return [[_name copy] autorelease]; } - (void)setName:(NSString *)value { [value retain]; [_name release]; _name = value; } 

È facile ora distinguere tra ivars e getter / setter. Gli accessors hanno il self. prefisso. Non dovresti comunque accedere direttamente alle variabili.


Il tuo codice di esempio non funziona come dovrebbe:

 _myVar = some_other_object; // _myVar is the ivar, not myVar. self.myVar = some_other_object; // works too, uses the accessors 

Una proprietà sintetizzata di nome prop è in realtà rappresentata da due metodi prop (restituendo il valore corrente della proprietà) e setProp: (impostazione di un nuovo valore per prop).

La syntax self.prop è zucchero sintattico per chiamare uno di questi accessor. Nel tuo esempio, puoi eseguire una delle seguenti myVar per impostare la proprietà myVar :

 self.myVar = @"foo"; // handles retain/release as specified by your property declaration [self setMyVar: @"foo"]; // handle retain/release _myVar = @"Foo"; // does not release old object and does not retain the new object 

Per accedere alle proprietà, utilizzare self.propname . Per accedere alle variabili di istanza utilizzare solo il nome della variabile di istanza.

Il problema con l’utilizzo della strategia @synthesize myVar = _myVar, è che ho pensato di scrivere codice come:

 myVar = some_other_object; // doesn't work. 

Il compilatore si lamenta che myVar non è dichiarato. Perché è così?

Perché la variabile myVar non è dichiarata.

Quella dichiarazione usa la syntax per accedere a una variabile, sia essa una variabile di istanza o qualche altro tipo. Come ha detto Scuotivento, per accedere a una proprietà, è necessario utilizzare la syntax dell’accesso alla proprietà ( self.myVar = someOtherObject ) o un messaggio esplicito al metodo accessor ( [self setMyVar:someOtherObject] ).

Altrimenti, stai tentando di accedere a una variabile e, poiché non hai una variabile denominata myVar , stai tentando di accedere a una variabile che non esiste.

In generale, nomino le mie proprietà allo stesso modo delle mie variabili di istanza; questo è l’assunto predefinito che fa la syntax @property . Se trovi che stai combattendo le impostazioni predefinite, stai sbagliando (o il tuo framework sux, che non è il caso per Cocoa / Cocoa-touch secondo me).

L’errore del compilatore che stai ottenendo è dovuto al fatto che l’uso delle proprietà deve sempre avere un riferimento a un object, anche all’interno della tua implementazione di class:

 self.stuff = @"foo"; // property setter [stuff release]; // instance variable stuff = @"bar"; // instance variable return self.stuff; // property getter 

So che molti programmatori di Cocoa non sono d’accordo, ma penso che sia una ctriggers pratica usare le proprietà all’interno dell’implementazione di class. Preferirei vedere qualcosa del genere:

 -(void) someActionWithStuff: (NSString*) theStuff { // do something [stuff release]; stuff = [theStuff copy]; // do something else } 

di questo:

 -(void) someActionWithStuff: (NSString*) theStuff { // do something self.stuff = theStuff; // do something else } 

Preferisco fare la gestione della memoria nel modo più esplicito ansible. Ma anche se non sei d’accordo, l’uso del modulo self.stuff indicherà a qualsiasi programmatore Objective-C esperto che stai chiamando una proprietà piuttosto che accedere a una variabile di istanza. È un punto delicato che è facile per i principianti sorvolare, ma dopo aver lavorato con Objective-C 2.0 per un po ‘, è abbastanza chiaro.

Don,

In base alle “regole”, è necessario chiamare Release per ogni copia, Alloc e Retain. Allora, perché stai chiamando Release su roba? Questo presuppone che sia stato creato utilizzando Alloc, Copy o Retain?

Questo fa sorgere un’altra domanda: è dannoso chiamare Release su un riferimento a un object se è già stato rilasciato?

Poiché Apple si riserva il prefisso _ per se stesso, e dal momento che preferisco renderlo più ovvio quando sto usando il setter e quando sto usando l’ivar, ho adottato il practive di usare un prefisso di i_ sui miei ivars, quindi per esempio :

 @interface MyClass : NSObject { NSString *i_myVar; } @property (nonatomic, retain) NSString *myVar; @synthesize myVar = i_myVar; i_myVar = [input retain]; self.myVar = anotherInput; [i_myVar release] 

Dal momento che è molto importante sapere quando si sta usando il setter e quando si utilizza l’ivar, trovo che il nome esplicitamente diverso sia più sicuro.

Nella tua domanda, dovrebbe essere:

 self.myVar = @"Foo"; // with setter, equivalent to [self setMyVar:@"Foo"] 

e

 _myVar = some_other_object; // direct ivar access - no memory management! 

Ricorda che non devi usare setters / getter in init / dealloc, quindi devi eseguire l’accesso diretto a ivar (e un’attenta gestione della memoria) in quei metodi.

cosa c’è di sbagliato semplicemente usando

 @interface MyClass : NSObject @property NSString *prop; @end 

non anatomici e ritentivi non sono richiesti, mantenere è il valore predefinito, e atomico / non anatomico non è importante a meno che XCode non ti avvisa.

NON è necessario dichiarare l’iVar, ne verrà creato uno per te chiamato _prop, se vuoi veramente usarne uno (non vedo perché sia ​​onesto)

@synthesize NON è richiesto.

quando (e dovresti) usare ARC non devi preoccuparti di mantenere e rilasciare entrambi.

mantienilo semplice!

inoltre, se hai un metodo come questo

 - (void)aMethod:(NSString*)string { self.prop = string; // shows very clearly that we are setting the property of our object _aName = string; // what is _aName ? the _ is a convention, not a real visual help } 

userei sempre le proprietà, più flessibile, più facile da leggere.