2013-03-26 13 views
9

Questo è stato chiesto molto, ma questa domanda è di ottenere esempi di quando si userebbe ciascuno di questi metodi. Si prega di utilizzare esempi diversi dal setter e dal ciclo infinito getteriOS, usando underscore vs usando iVar direttamente

esempio.

.h -
@property(nonatomic, strong)NSMutableArray* mutArray
.m -
@synthesize mutArray= _mutArray;

1) dovrei voler:
_mutArray = [[NSMutableArray alloc] init];
O
self.mutArray=[[NSMutableArray alloc] init];
Perché avrei dovuto fare ciascuno di loro, e qual è la differenza ?!

2) Se voglio aggiungere un oggetto ad esso ...
[_mutArray addObject:object];
O
[self.mutArray addobject:object];

e perché ?!

Grazie mille!

risposta

12

Si dovrebbe trattare solo con i tuoi Ivars in init e dealloc o dove assolutamente richiesto da un dettaglio di implementazione (come ad esempio all'interno della funzione di accesso per sé, o in cui è effettivamente necessario un indirizzo di memoria). Oltre che in quei luoghi, è necessario utilizzare sempre l'accessor, ovvero [self foo] anziché _foo.

self.foo è solo zucchero sintattico attorno alla chiamata effettiva, ovvero [self foo]. È importante capire che lo self.foo è un invio di messaggi ObjC standard e significa esattamente la stessa cosa di [self foo]. Per convenzione, si dovrebbe usare la sintassi del punto solo quando ci si riferisce alle proprietà.

Pre-ARC, l'uso diretto di ivars è stata la causa n. 1 di arresti anomali nella mia esperienza.La probabilità che si rovini quando si assegna direttamente ad un ivar senza ARC si avvicina rapidamente al 100% sull'ambito del programma.

Dal momento che ARC, continuo a sostenere che dovresti sempre usare gli accessor (con le eccezioni indicate sopra), ma le ragioni sono più sottili. La ragione principale è che un accessor può essere personalizzato, sia nella classe corrente, in una sottoclasse, sia tramite KVO (che accade al di fuori del tuo codice interamente). Se accedi direttamente a Ivar, allora ignorerai questo. Ad esempio, diciamo che la proprietà è pigramente creata (che è piuttosto comune). Quindi se usi ivar prima che venga creato, otterrai dei bug sottili. Quindi devi ricordare, per quella proprietà, di usare sempre l'accessor. Allo stesso modo, è possibile chiamare setNeedsDisplay o pubblicare una notifica o simili.

Se si dispone di una regola semplice che dice "userò sempre gli accessor", è facile guardare il codice e sapere che è giusto. Nei pochi casi in cui è necessario aggirare l'accessor, lo _ dice "ciao, fai attenzione qui, sto facendo qualcosa di strano".

Se si dispone di una regola "Utilizzerò le utilità di accesso per le proprietà che ne hanno bisogno, ma non per quelle che non lo richiedono", è quasi impossibile consultare il codice e sapere se è corretto. Lo sviluppatore precedente ha usato l'ivar perché era necessario o solo perché ne aveva voglia? Puoi cambiarlo o no? È molto difficile sapere.

Quindi, anche dopo l'ARC, l'uso costante degli accessor è una buona programmazione difensiva e lo consiglio vivamente.

+0

Beh, questo è super conflitto con la risposta di Ragnar! Cosa ne pensi del mantenimento extra aggiunto passando per il setter? E anche il fatto che altre persone potrebbero lavorare con il codice e cambiare i setter/getter portando a risultati inaspettati? – jgvb

+0

Il mantenimento "extra" non è "extra". È necessario conservare ciò che si deve applicare e l'accessor è il posto giusto per farlo (ciò vale solo per la pre-ARC, ma non riuscendo ad applicarlo correttamente è la causa principale dei crash che ho menzionato). Vuoi usare esattamente gli accessors * perché * altre persone potrebbero lavorare sul codice, e non c'è modo di garantire che tutti sappiano e seguano sempre "quando cambi questo ivar, devi anche ..." Il modo corretto per documentare che il requisito personalizzato è attraverso l'accessor. –

+0

Occasionalmente questo porterà a risultati sorprendenti (ricalcolare qualcosa troppo spesso, per esempio), ma quegli effetti collaterali sono quasi sempre nella mia esperienza molto più facile da debugare del fatto che non sapevi che dovevi chiamare 'setNeedsDisplay' dopo aver impostato l'ivar. Ciò porta a cose che "tipo di lavoro, tranne quando non lo fanno", che sono estremamente difficili da eseguire il debug. L'esecuzione di una funzione di accesso quando non sapevi che si sarebbe verificato si presentava nella traccia dello stack. Non riuscendo a eseguire una funzione di accesso che non sapevi di dover eseguire ... è difficile da trovare. –

0

_mutArray è l'iVar, self.mutArray accede alla proprietà tramite getter e setter creati per te quando @sintendi la proprietà. Puoi sovrascrivere questi getter e setter a causa di cose personalizzate. Nel tuo esempio, la tua proprietà è impostata su strong, che aggiunge un retain alla tua proprietà. Quindi self.mutarray = [[NSMutableArray alloc] init]; farebbe una cosa del genere (a meno che non sovrascrivere setter della struttura):

-(void)setMutarray:(NSMutableArray*)_mutArray{ 
    if(_mutArray != mutArray){ 
     [mutArray release]; 
     mutArray = nil; 
     mutArray = [_mutArray retain]; 
    } 
} 

Per aggiungere oggetti a un array si vorrebbe accedere solo l'iVar, non la proprietà a meno che non si sta facendo qualcosa di personalizzato nel getter . Per esempio siete getter potrebbe assomigliare a questo:

-(NSMutableArray*)mutArray{ 
    if(!mutArray){ 
     self.mutArray = [[[NSMutableArray alloc] init] autorelease]; 
    } 
    return mutArray; 
} 

in questo modo si potrebbe garantire che hai sempre avuto una vera e propria matrice per aggiungere oggetti a. Se questo è il caso, si vorrebbe usare [self.mutArray addObject: object];

Quindi, a meno che tu non voglia fare qualcosa di personalizzato nel getter o nel setter, vuoi semplicemente accedere a iVar.

+0

Perché io non voglio passare attraverso il setter e getter a meno personalizzare? – jgvb

+0

Non si vuole passare attraverso il setter perché aggiungerà un retain. Inoltre, se altre persone stanno lavorando con il codice, potrebbero fare qualcosa nel getter o setter che non stai tenendo in considerazione. –

+0

Grazie mille – jgvb

0

self È keyword come thiskeyword in JAVA.

Accede all'oggetto corrente e inoltre è un puntatore a un oggetto.

for more info about self read this tutorial

_ObjeName è chiamato iVar in Objective c

variabili di istanza dichiarate nella realizzazione sono implicitamente nascosti (efficacemente privato) e la visibilità non può essere modificato - @public, @protected and @private non producono errori di compilazione (con la corrente Clang almeno) ma vengono ignorati.

Per esempio:

diverso tra

1)NSString *someString = _name;

2)NSString * someString = self.name;

Si supponga di avere nel file .m questa linea (e non hanno alcun metodo sovrascritto per dirigere l'accesso a _name)

@synthesize name = _name; 

E significa che la proprietà name (self.name) utilizzerà _name variabile quando si tenta di accedervi.In questo caso è pari a self.name _name


Ma se si dispone di proprietà dinamica per il nome, qualcosa di simile:

-(NSString)name{ 
    return @"1234"; 
} 

poi c'è una differenza. self.name restituirà sempre 1234, ma _name non può essere uguale a questo valore.

Esempio:

_name = @"555"; 
NSLog(_name); 
NSLog(self.name); 

Risultato:

2012-02-09 14:27:49.931 ExampleApp[803:207] 555 
2012-02-09 14:27:49.933 ExampleApp[803:207] 1234 

Above Example I Got From this Question.

+2

Dire che 'self' è come 'this' è estremamente confuso per i nuovi sviluppatori. 'questo' può essere implicito su Java. 'self' non è mai implicito in ObjC. Questo porta a molta confusione quando gli ex sviluppatori Java pensano che '_name' e' self.name' significano sempre esattamente la stessa cosa. Non sono mai identici, generano sempre un codice assembler diverso, possono solo capitare di restituire lo stesso risultato. –

+0

@RobNapier +1. Sono venuto da sfondo Java a ObjC e stavo facendo anche il paragone con 'this' e' self' che, sebbene correlati, sono una cosa diversa. – Petar

Problemi correlati