ETA: @DougW fa giustamente notare che di una proprietà di tipo proprietario (assign
/retain
/copy
) non influenza il getter. Influisce ancora sul setter. Per i tipi readonly
, ciò è importante se si sostituisce la parte readonly
della dichiarazione in un'estensione di classe, quindi è possibile utilizzare il setter all'interno dell'implementazione. Un override della proprietà dell'estensione di classe è consentito solo per modificare lo stato readonly
della proprietà, quindi il resto di esso, ovvero i tipi di atomicità e proprietà, deve essere dichiarato in modo appropriato nell'intestazione. Anche se non stai sovrascrivendo la proprietà ora, potresti farlo in futuro, quindi potresti anche documentare come vuoi che la memoria sia gestita da te usando l'opzione corretta per cominciare.
Il conteggio dei riferimenti automatico (ARC) modifica i dettagli di implementazione del runtime sovrapponendo le proprie regole di gestione della memoria in aggiunta alle classiche regole del conteggio, ma le regole e i consigli per la configurazione delle proprietà rimangono invariati.
Perché usare retain
con readonly
? Se si contrassegna una proprietà come retain
, la funzione di accesso sintetizzato fa qualcosa di simile:
/* getter for retain property */
- (NSString *)name {
return [[name retain] autorelease];
}
Ora, se l'oggetto inviato -name
ai cambiamenti del nome, mentre si sta ancora usando, il codice chiamante avrà ancora un riferimento valido a una stringa.Se ha dichiarato come assign
, però, sarebbe come questo:
/* getter for assign property */
- (NSString *)name {
return name;
}
Ora, non appena il nome viene cambiato l'oggetto, dovrà essere rilasciato per evitare una perdita, invalidando la chiamata riferimento del codice. Lo/sta davvero affermando un criterio di gestione della memoria: retain
/copy
dice "Prometto che tengo un riferimento all'originale/una copia del valore che fornisco qui", mentre assign
dice "Ho appena il valore e non rivendicare alcun riferimento proprietario a questo. "
Quando il valore non ha bisogno di gestione della memoria, ad esempio un semplice int
, quindi assign
ha senso. Se non stai mantenendo intenzionalmente un oggetto, ad esempio un delegato, allora assign
ha senso. Ma, nella maggior parte degli altri casi, vorrai retain
o copy
.
Inoltre, il file di implementazione può sostituire solo la parte readwrite
/readonly
di una dichiarazione di proprietà, non la parte di gestione della memoria. Come dichiarato, il file può avere .m
:
setter
@interface Holiday (/*class extension*/)
@property(nonatomic, retain, readwrite) NSDate *date;
/* override other properties to make them readwrite... */
@end
non pubblici per le dichiarazioni di proprietà ignorati verranno poi sintetizzati insieme alle funzioni di accesso pubblici.
Perché non utilizzare setter/accessori durante -init
? Perché setter/di accesso eseguono spesso notifica KVO, che si vuole evitare, mentre l'oggetto non è completamente inizializzato, cioè durante -init
(quando è mezza inizializzato sul suo modo di piena inizializzazione) e -dealloc
(quando è mezza inizializzato sul suo modo di essere completamente non inizializzato).
Perché utilizzare copy
con readonly
? Come in risposta alla sua prima domanda: perché se copy
contro retain
contro assign
colpisce sia i setter ei getter. Un getter copia sarebbe simile a questa:
/* getter for copy property */
- (NSString *)name {
return [[name copy] autorelease];
}
Perché a volte copy
e talvolta retain
?copy
viene generalmente utilizzato con oggetti valore (oggetti passivi che rappresentano un valore); retain
viene generalmente utilizzato con altri oggetti. A volte, i problemi di efficienza entrano in gioco (molto probabilmente prematuramente ...) e potresti scegliere di utilizzare retain
dove normalmente utilizzerai lo copy
.
Come utilizzare copy
/retain
insieme a readonly
qui? Praticamente come loro. Sostituire le dichiarazioni in un'estensione di classe in modo da poter utilizzare i setter per modificare i valori delle proprietà al di fuori di -init
e -dealloc
, dove utilizzerei solo l'accesso diretto alle variabili d'istanza. Vorrei anche nil
le ivars dopo di loro rilascio in -dealloc
, per esempio,
[name release], name = nil;
Questo permette di evitare l'invio di messaggi o altro riferimento a un oggetto già rilasciato.
** le proprietà di ritenzione non anatomiche ** restituiscono solo il puntatore. Loro ** non fanno il fermo, cosa autorelease. Vedi la sezione ** atomicity ** dei documenti http://developer.apple.com/library/ios/# documentation/cacao/concettuale/oggettivoC/articoli/ocProperties.html – JeremyP
@JeremyP: buona chiamata. La decisione di non "[autorizzare il [[foo retain] autorelease]' in accessors non atomici ha senso: se si manterrà il valore più a lungo del ciclo di runloop corrente, si dovrebbe tenerlo da solo. Se stai usando 'nonatomic', stai fondamentalmente affermando che la sicurezza del thread non è una preoccupazione. Se non ti devi preoccupare della sicurezza dei thread, allora nessun codice da parte tuo verrà eseguito mentre stai usando il valore di ritorno dalla funzione di accesso, quindi non è necessario che l'accessore esegua "[[foo retain] autorelease]' . –
@Jeremy: Direi che usare mezzi non anatomici significa affermare che la robustezza non è una preoccupazione - o è meno preoccupante delle prestazioni. Impostare le proprietà su nonatomico senza prima profilare il codice conta come un'ottica prematura nel mio libro. – JeremyP