Quando dovrei rilasciare oggetti in - (void) viewDidUnload piuttosto che in -dealloc?


Risposte:


51

Oltre a quanto già indicato, ho voluto approfondire la logica sottostante -viewDidUnload.

Uno dei motivi più importanti per l'implementazione è che le UIViewControllersottoclassi comunemente contengono anche riferimenti di proprietà a varie sottoview nella gerarchia della vista. Queste proprietà potrebbero essere state impostate IBOutletsdurante il caricamento da un pennino o in modo programmatico all'interno -loadView, ad esempio.

La proprietà aggiuntiva delle viste secondarie UIViewControllersignifica che anche quando la sua vista viene rimossa dalla gerarchia della vista e rilasciata per risparmiare memoria, attraverso la quale anche le viste secondarie vengono rilasciate dalla vista, non verranno effettivamente deallocate perché la UIViewControllerstessa contiene ancora il proprio in sospeso mantenendo i riferimenti anche a quegli oggetti. Il rilascio della UIViewControllerproprietà aggiuntiva di questi oggetti garantisce che verranno deallocati anche per liberare memoria.

Gli oggetti che rilasci qui vengono solitamente ricreati e impostati di nuovo quando la UIViewControllervista è re-loaded, da un pennino o tramite un'implementazione di -loadView.

Notare inoltre che la UIViewController viewproprietà è nilquando viene chiamato questo metodo.


1
Dovresti leggere developer.apple.com/library/ios/#featuredarticles/… per comprendere il ciclo di vita del controller di visualizzazione / visualizzazione
Paul Solt,

21

Come dice la documentazione :

Viene chiamato durante le condizioni di memoria insufficiente quando il controller della vista deve rilasciare la sua vista e tutti gli oggetti associati a quella vista per liberare memoria.

Nella stessa situazione nondealloc viene chiamato. Questo metodo è disponibile solo in OS3 e versioni successive. Affrontare la stessa situazione in iPhone OS 2.x è stato un vero dolore!

Aggiornamento luglio 2015 : va notato che è viewDidUnloadstato deprecato in iOS 6 perché "le visualizzazioni non vengono più eliminate in condizioni di memoria insufficiente e quindi questo metodo non viene mai chiamato". Quindi, il consiglio moderno è di non preoccuparsene e di usarlo dealloc.


6
Anche dai documenti: "Dovresti farlo solo per oggetti che puoi facilmente ricreare in seguito, nel tuo metodo viewDidLoad o da altre parti della tua applicazione. Non dovresti usare questo metodo per rilasciare dati utente o altre informazioni che non possono essere facilmente ricreabile ". Questa è una domanda che avevo anch'io, grazie!
leolobato

E se la vista è attualmente visibile? Non sarebbe male lasciarlo cadere a causa di un avviso di memoria insufficiente? ;) quindi l'app sarebbe vuota e vuota. Non ho il punto di rilasciare la visualizzazione a causa della scarsa memoria. Se non vedo una vista, rilascio sempre l'intero controller. Althogh ho un controller di visualizzazione root che rimane intatto e gestisce tutto il caricamento / scaricamento dei controller di visualizzazione figlio ...
Grazie

No, non lo useresti se cambiassi una vista con un'altra. Pensa al caso in cui hai uno "stack" di visualizzazioni con un UINavigationController. È visibile solo una vista e, se hai un avviso di memoria, puoi rilasciare tutte quelle che non sono visibili.
Stephen Darlington,

Come si controlla che viewDidUnload non venga chiamato nella vista visibile corrente come ha notato Thanks?
Arielcamus

1
viewDidUnload non verrà chiamato sulla vista attualmente visibile, solo sulle viste che non sono visibili.
programma

9

Questo perché tipicamente imposterai @propertycome "(nonatomic, retain)"e come tale il setter creato per te rilascia l'oggetto corrente e quindi mantiene l'argomento ie

self.property = nil;

... fa qualcosa sulla falsariga di:

[property release];
property = [nil retain];

Quindi stai uccidendo due piccioni con una fava: gestione della memoria (rilasciando l'oggetto esistente) e assegnando il puntatore a zero (poiché l'invio di qualsiasi messaggio a un puntatore zero restituirà zero).

Spero che aiuti.


8

Ricorda che viewDidUnloadè un metodo nel controller della vista, non nella vista. Il metodo della vista dealloc verrà chiamato quando la vista viene scaricata, ma il metodo del controller della vista dealloc potrebbe non essere chiamato se non in un secondo momento.

Se ricevi un avviso di memoria insufficiente e la tua vista non viene visualizzata, cosa che accadrà ad esempio ogni volta che utilizzi un UIImagePickerController per consentire all'utente di scattare una foto, la tua vista verrà scaricata e dovrà essere ricaricata dopo.


questo ha senso. Cosa succede se rilascio sempre l'intero controller della vista? Questo è quello che faccio effettivamente. In questo caso non ho molto a che fare con -viewDidUnload, giusto? Non ho mai avuto la situazione in cui avrei abbandonato solo la vista, dal momento che lascio sempre l'intero controller se non è comunque visibile.
Grazie

bene, ricorda solo che nel caso in cui la tua vista sia mostrata, ma hai una vista a schermo intero come ImagePicker sopra di essa, la tua vista potrebbe essere scaricata anche se non avevi pianificato che fosse.
David Maymudes

6

Conclusione:

I controller di visualizzazione hanno una proprietà di visualizzazione. In genere un pennino o un pezzo di codice aggiunge altre visualizzazioni a questa visualizzazione. Questo accade spesso all'interno di un metodo -viewDidLoad, come questo:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

inoltre, un file pennino può creare un pulsante e aggiungerlo alla vista del controller di visualizzazione.

Su iPhone OS 2.2, quando -didReceiveMemoryWarning veniva invocato dal sistema, dovevi rilasciare qualcosa per liberare memoria. Potresti rilasciare la visualizzazione dell'intero controller della vista se avesse senso. O solo grandi contenuti che consumano memoria.

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

Ora, nel nuovo OS 3.0, c'è un metodo -viewDidUnload, che verrà richiamato dal sistema quando la vista è stata scaricata a causa della memoria insufficiente (correggimi: quando viene chiamato esattamente?)

-viewDidUnload viene utilizzato per rilasciare tutti gli oggetti che erano di proprietà sia del controller della vista stesso che della vista. Il motivo: se un controller di visualizzazione contiene riferimenti a elementi secondari della visualizzazione, ad esempio un pulsante, le visualizzazioni secondarie a cui si fa riferimento non verranno rilasciate, perché il loro numero di conservazione è> = 1. Dopo che sono state rilasciate in -viewDidUnload, possono essere liberate dalla memoria.


1
ricordo in vista ha scaricato per fare self.button = nil ;, non [pulsante di rilascio] ;.
mk12

6

Apple ha deprecato viewWillUnload, ora dovresti usare didReceiveMemoryWarning o dealloc per rilasciare i tuoi oggetti.

In iOS 6, i metodi viewWillUnload e viewDidUnload di UIViewController sono ora deprecati. Se stavi usando questi metodi per rilasciare i dati, usa invece il metodo didReceiveMemoryWarning. È inoltre possibile utilizzare questo metodo per rilasciare riferimenti alla vista del controller di visualizzazione se non viene utilizzato. Dovresti verificare che la vista non sia in una finestra prima di farlo.


5

Se il controller di visualizzazione viene estratto dallo stack del controller di navigazione e non viene mantenuto altrove, verrà deallocato e verrà chiamato dealloc invece di viewDidUnload. Dovresti rilasciare le viste create in loadView in dealloc, ma non è necessario impostare le variabili a zero, perché subito dopo aver chiamato dealloc le variabili non esisteranno più.


3

Puoi rilasciare tutte le visualizzazioni secondarie a cui tieni, ad esempio quell'UIImageView che hai mantenuto nel tuo metodo loadView, o meglio ancora l'immagine che era su quell'UIImageView.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.