In un dispositivo come l’iPhone, dove la memoria è limitata e preziosissima, un corretto uso di allocazione e deallocazione degli oggetti presenti nelle nostre interfacce grafiche (e non solo) è una argomento molto delicato ed importante. A testimoniarlo è la stessa classe UIViewController che, come credo abbiate potuto notare, implementa dei metodi specifici per la gestione di questo aspetto. Vediamo oggi, con questo articolo, come usare al meglio i metodi messi a disposizione per la gestione della memoria.
Ecco i tre metodi della classe UIViewController per la memoria:
- (void)didReceiveMemoryWarning;
- (void)loadView;
- (void)viewDidUnload;
In questo articolo impareremo l’uso degli ultimi due.
Premetto che personalmente non uso Interface Builder, in quanto preferisco costruire le mie interfacce grafiche da codice, a parer mio, in questo modo, tutto è più facile e gestibile, (anche se capisco che non per tutti è così). In questo articolo, però, se non siete amanti del codice sforzatevi un minimo, perchè la semplice interfaccia grafica dell’esempio che sto per mostrarvi verrà creata via codice.
– (void)loadView
Questo metodo viene chiamato non appena occorre caricare una vista per mostrarla all’utente. Quindi in questo metodo bisogna definire la vista del nostro UIViewController creando la view principale e aggiungendoci altri elementi grafici etc. Da notare che quando alloco e inizializzo un UIViewController non alloco in realtà memoria per la vista, questa verrà allocata solo quando servirà mostrarla.
Ecco un esempio nel quale abbiamo un UIButton e una UITableView tra le proprietà del nostro controller:
- (void)loadView {
UIView *controllerView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
button = [[UIButton buttonWithType:UIButtonTypeInfoLight] retain];
[controllerView addSubview:button];
tableView = [[UITableView alloc] initWithFrame:controllerView.frame style:UITableViewStylePlain];
[controllerView addSubview:tableView];
[self setView:controllerView];
[controllerView release];
}
Ora immaginiamo di avere un UINavigationController nel quale facciamo 1000 push di 1000 istanze di questo UIViewController… verrà allocata tanta memoria, ma l’utente vedrà sicuramente solo l’ultimo dei UIViewController, quindi il sistema quando riceve un avviso di “memoria esaurita” lo notificherà a tutti gli UIViewController e quelli non visibili ( 999 istanze ) eseguiranno automaticamente il metodo -(void)viewDidUnload nel quale vengono rilasciati tutti gli oggetti grafici (e non solo) che non servono al momento. Più precisamente in questo metodo bisogna rilasciare gli oggetti che sono stati allocati nel metodo -(void)loadView, infatti, non appena il UIViewController tornerà visibile, verrà chiamato questo metodo che ricaricherà la grafica.
Ecco come implementare il metodo:
- (void)viewDidUnload {
[super viewDidUnload];
;
button = nil;
[tableView release];
tableView = nil;
}
Alcune considerazioni:
- il metodo viene richiamato alla superclasse in caso abbia da rilasciare anche lei qualcosa che noi ovviamente non sappiamo
- oltre a rilasciare un oggetto dobbiamo anche eguagliarlo a “nil”, ma perchè?
Mettiamo il caso qualcuno chiami un metodo che usa un nostro oggetto, se l’ggetto è stato rilasciato, ma esiste allora avremmo un errore (crash) infatti useremmo un oggetto molto probabilmente deallocato. Se invece è uguale a “nil” allora ogni metodo applicato a questo oggetto quindi a “nil” non avrebbe nessun effetto!
Riassumendo
In -(void)loadView carico gli elementi che mi servono quando il controller è visibile (non necessariamente solo la grafica, anche array o altro).
In -(void)viewDidUnload chiamo il metodo della superclasse e rilascio ed eguaglio a “nil” tutti e soli gli oggetti allocati nel loadView.
Spero vi sia utile, alla prossima 🙂
One Response to “L#016 – Gestione della memoria: UIViewController, loadView e viewDidUnload”
29 Marzo 2011
AlessandroGrazie mille, preziosi come sempre.