Objective-C Gestione della memoria Setter
-
13-09-2019 - |
Domanda
Ancora un po 'confuso circa la gestione della memoria Objective-C. Credo che la mia confusione deriva da ciò che esattamente l'autorelease significa.
NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];
Ora, che cosa devo fare con l'accountDictionary nel metodo setAccountDictionary del mio controller della vista? In questo momento ho appena impostato l'istanza variabile "accountDictionary" a tutto ciò che viene restituito. Devo impostare ad un conservato uno, e poi rilasciare quello che è tornato? Quale dovrebbe essere il mio codice setter blocco simile, dato che il metodo PropertyList di NSString è autoreleased?
A proposito, se io rilascio theBackendResponse, perderò l'accountDictionary? Io non presumo ...
Soluzione
La chiamata [objectInstance autorelease]
aggiunge un oggetto alla NSAutoreleasePool
corrente. Quando quella piscina riceve un messaggio drain
, invia un release
a tutti gli oggetti nel pool. Se uno qualsiasi di tali oggetti retainCount raggiunge 0, essi si rilasciano in quel punto. Lo scopo di autorelease è quello di permettere di contrassegnare un oggetto per essere rilasciato "po 'di tempo in futuro". Ciò è particolarmente utile per le cose come i metodi che restituiscono un oggetto appena allocato ma vogliono rilasciarlo in modo che il chiamante non deve assumere la proprietà dell'oggetto restituito. Un metodo potrebbe assomigliare a questo:
- (id)myMethod {
id myObj = [[SomeClass alloc] init];
...
return [myObj autorelease];
}
Il chiamante di myMethod
allora retain
il valore restituito se volevano assumere la proprietà del valore restituito o ignorarlo, se non. Quando il NSAutoreleasePool
corrente viene svuotato, myObj
otterrà un messaggio di rilascio. Se non ci sono altri oggetti possiedono esso (cioè hanno inviato un messaggio retain
), si otterrà deallocato.
Tutto questo è spiegato nel cacao Memory Management Guida di programmazione . Anche se avete già letto, vale sempre la pena un'altra lettura.
Quindi, per rispondere alle vostre domande:
In primo luogo, si dovrebbe rilasciare theBackendResponse
. Potrai perdere la memoria se non lo fai. Non hai bisogno di sapere che cosa accountDictionary
fa con la stringa: se ha bisogno di mantenere un riferimento avrà mantenuto theBackendResponse
. Hai una proprietà di theBackendResponse
perché alloc
'd esso, quindi è necessario rinunciare a che la proprietà (via release
o indirettamente tramite autorelease
).
In secondo luogo, è necessario mantenere o copiare l'argomento per setAccountDictionary:
se si desidera mantenere, rispettivamente, un riferimento a tale oggetto o il valore. Il metodo standard setter simile a questa (supponendo che non hai bisogno di semantica atomiche):
-(void)setAccountDictionary:(NSDictionary*)newDict {
if(newDict != accountDictionary) {
id tmp = accountDictionary;
accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
[tmp release];
}
}
Si deve anche ricordare a release
accountDictionary nel metodo dealloc:
- (void)dealloc {
[accountDictionary release];
[super dealloc];
}
Dal momento in cui sembra essere utilizzando NSViewController
, presumo che sei su Leopard (OS X 10.5), nel qual caso, si dovrebbe probabilmente essere utilizzando @property
e il @synthesize
d getter / setter, se possibile. Per fare questo, aggiungere un
@property (copy,readwrite) NSDictionary * accountDictionary;
dichiarazione alla @interface
di classe. E aggiungere una direttiva @synthesize accountDictionary;
nel blocco @implementation
per la classe di controllo.
Altri suggerimenti
In generale, un oggetto o di un metodo non dovrebbe avere a cuore come un altro è la memoria di gestione. Il fatto che qualcun altro ha autoreleased qualcosa è irrilevante per voi. E 'più semplice pensare al concetto di proprietà . Così retain
ed alcuni altri metodi reclama diritti di proprietà, e release
e autorelease
rinunciare ad essa. Se un oggetto ha bisogno di mantenere un riferimento a un altro, dovrebbe rivendicare la proprietà per tutto il tempo di cui ha bisogno. Così, i metodi setter di solito o mantenere o copiare il nuovo valore e rilasciare o autorelease il vecchio valore.
Vi consiglio vivamente la lettura le linee guida di gestione della memoria di cacao . Non sono tutti così a lungo o complicato, ed è molto importante per capirle.
Il metodo di accesso set dovrebbe sempre copy
/ retain
il valore in ingresso prima di rilasciare il vecchio, nel caso in cui il valore precedente è l'unico oggetto che possiede il nuovo valore:
-(void)setAccountDictionary:(NSDictionary*)newDict {
id old = accountDictionary;
accountDictionary = [newDict copy];
[old release];
}
Se accountDictionary
cui newDict
e il conteggio conservarlo per newDict
è stato 1, la chiamata a [accountDictionary release]
prima della chiamata a [newDict copy]
causerebbe il conteggio mantenere a avuto modo di 0 e quindi rilasciare newDict
.
Come esempio di codice errato, in cui rilasciamo vecchio dizionario e quindi copiare il nuovo dizionario:
-(void)setAccountDictionary:(NSDictionary*)newDict {
[accountDictionary release];
accountDictionary = [newDict copy];
}
e hanno il seguente codice:
NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];
E 'forzato, ma dimostra che nel setter, accountDictionary
e newDict
si riferiscono alla stessa istanza. Se il conteggio di conservare è 1, la linea [accountDictionary release]
diminuirà il conteggio di conservare a 0, e quindi rilasciare l'istanza dalla memoria. [newDict copy]
ora riferimento a un'istanza valido.
di Apple descrive diversi concetti in sede di attuazione di accesso: gestione della memoria Accessor metodi
Se è possibile utilizzare Objective-C 2.0, vorrei andare con proprietà e sintassi del punto.
Le proprietà sono di nuovo in Objective-C 2.0 e forniscono automaticamente la generazione di accesso.
Nel file .h:
@property (retain) NSDictionary* accountDictionary;
Per l'attuazione:
@synthesize accountDictionary;
Sintetizzare genera metodi di accesso per il vostro NSDictionary. (Se si desidera fornire la propria implementazione, si potrebbe anche farlo)