Domanda

Sfondo :

Ho un'applicazione per la barra delle schede. Ciascuna scheda contiene un controller di navigazione che consente all'utente di passare da una vista all'altra mostrando informazioni dettagliate sui dati (ogni vista è gestita da un controller di vista e ogni classe di controller di vista ha il metodo didReceiveMemoryWarning). Gli elenchi vengono compilati estraendo i dati dai servizi Web.

problema :

Quando uso " Hardware > Simula avviso di memoria & Quot; opzione di iPhone Simulator, il metodo viewDidLoad viene chiamato per TUTTI i miei controller di visualizzazione, anche quello che l'utente sta visualizzando. Non desidero cancellare alcun contenuto utilizzato dal controller di visualizzazione attivo. Come posso raggiungerlo?

Quale metodo dovrebbe avere l'implementazione per ricaricare i dati dopo che i dati sono stati rilasciati a causa di un avviso di memoria? (Vedo che le classi del controller di visualizzazione che contengono una vista tabella chiamano il metodo loadView quando l'utente torna a quella vista, ma se la vista contiene (diciamo UIWebView), il metodo [super didReceiveMemoryWarning] non viene chiamato. Perché? ”

Modificato (venerdì 30 gennaio 2009 - 15:10)

(Nota: sto usando Interface Builder per creare viste e il metodo [self setView:nil] è commentato.)

Quindi, quando un controller di visualizzazione riceve un messaggio di avviso di memoria, questi sono i passaggi che vengono eseguiti:

  1. Viene chiamato il seguente metodo:

    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning]; 
    }
    
  2. Come risultato della chiamata a setView, myObject = nil viene chiamato automaticamente?

  3. Se è necessario cancellare eventuali risorse, il metodo myObject deve essere sovrascritto per cancellare le risorse locali.

  4. dealloc non viene chiamato se la vista è attualmente attiva (per impostazione predefinita). Destra? - Sono davvero curioso di sapere quale metodo prende questa decisione e come?

Puoi per favore confermare. Inoltre, ho riscontrato un errore seguendo questo approccio, ma l'aggiunta di <=> dopo aver rilasciato <=> nel <=> metodo della classe controller ha risolto il problema. Grazie.

È stato utile?

Soluzione

Questa è una vecchia domanda, ma non vedo una risposta adeguata, quindi ecco qui:

Quando viene ricevuto un avviso di memoria, -didReceiveMemoryWarning viene chiamato in TUTTI i controller di visualizzazione, indipendentemente dal fatto che siano i " attuali " uno o no. I controller di visualizzazione stanno semplicemente ascoltando la trasmissione dell'evento di avviso di memoria.

Se la vista del controller di visualizzazione non viene utilizzata al momento dell'avviso di memoria, il controller lo scaricherà impostando la proprietà su zero. Come fa a sapere se viene utilizzata la vista? Dalla proprietà -superview della vista. Se view.superview è zero, la vista non fa parte di alcun albero e può essere scaricata in modo sicuro.

Una volta che ciò accade, viene chiamato il controller -viewDidUnload. Questo è il posto giusto per scaricare eventuali punti vendita e tutto ciò che verrà ricreato in -viewDidLoad.


A cosa serve _data? Il controller potrebbe avere oggetti che non vengono istanziati fino all'accesso. Ad esempio, potresti avere un controller che a volte necessita di una grande mole di dati da un file, ma non sempre. Potresti avere una proprietà impostata per questo in questo modo:

- (NSData*)bigChunkOfData {
  // Get data from our instance variable _data, read from disk if necessary
  if (_data == nil) {
    _data = [[NSData alloc] initWithContentsOfFile:@"/path/to/data"];
  }
  return _data;
}

Questo leggerà i dati dal disco questa volta per la prima volta, quindi li manterrà in una variabile di istanza. Poiché la variabile <=> viene creata su richiesta, è sicuro scaricarla in situazioni di memoria insufficiente: verrà creata di nuovo la prossima volta che ne avremo bisogno.

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];

  [_data release];
  _data = nil;  // <-- Very important: don't leave strong references dangling.
}

Altri suggerimenti

Faccio la mia pulizia in questo modo:

-(void)setView:(UIView*)view
{
    [super setView:view];
    if(view == nil)
    {
       // Our view has been cleared, therefore we should clean up everything 
       // we are not currently using
....

setView:nil viene chiamato da UIViewController in risposta a un avviso di memoria, se quella vista non è attualmente visibile - che è fondamentalmente ciò che vuoi sapere.

A CURA

In risposta ai follow up:

  1. Corretto.
  2. Questo è quello che faccio, e funziona per me.
  3. Una corretta. L'implementazione di didReceiveMemoryWarning in UIViewController è ciò che fa. Se non esegui l'override <=>, verrà chiamata l'implementazione della classe di base in UIViewController - se lo esegui, ovviamente dovresti chiamare:

    [super didReceiveMemoryWarning]
    

Per essere sicuro di non doverlo gestire per ogni singolo viewcontroller che scrivo .. Ho appena creato un modello Xcode ViewController che fornisce linee guida su quali oggetti rilasciare e quando ..

maggiori spiegazioni qui http: //iphone2020.wordpress.com/2010/05/30/efficient-memory-handling-in-uiviewcontroller-part-1/

Spero che trovi utile.

Per quanto riguarda la gestione della vista e gli avvisi di memoria:

UIKit non & # 8217; non consente solo la navigazione indietro da un controller di visualizzazione, ma consente anche la navigazione verso altri controller di visualizzazione da quelli esistenti. In tal caso, un nuovo UIViewController verrà allocato e quindi caricato in vista. Il vecchio controller di visualizzazione si spegne dallo schermo e diventa inattivo, ma possiede ancora molti oggetti & # 8211; alcuni in proprietà e variabili personalizzate e altri nella proprietà / gerarchia della vista. E così fa il nuovo controller di vista visibile, per quanto riguarda i suoi oggetti vista.

A causa della quantità limitata di memoria dei dispositivi mobili, possiede i due insiemi di oggetti & # 8211; uno nel controller di visualizzazione fuori schermo e un altro nel controller di visualizzazione su schermo & # 8211; potrebbe essere troppo da gestire. Se lo ritiene necessario, UIKit può recuperare parte della memoria del controller di visualizzazione off-screen & # 8217; che non viene comunque mostrata; UIKit sa quale controller di visualizzazione è sullo schermo e quale è off-screen, come del resto è quello che li gestisce (quando chiami presentModalViewController:animated: o dismissModalViewControllerAnimated:). Quindi, ogni volta che si sente sotto pressione, UIKit genera un avviso di memoria, che scarica e rilascia la vista fuori schermo dalla gerarchia della vista, quindi chiama il tuo metodo viewDidUnload personalizzato affinché tu faccia lo stesso per le tue proprietà e variabili. UIKit rilascia automaticamente self.view, permettendoci quindi di rilasciare manualmente le nostre variabili e proprietà nel nostro codice viewDidUnload. Lo fa per tutti i controller di visualizzazione fuori schermo.

Quando la memoria del sistema è insufficiente, viene emesso un didReceiveMemoryWarning. Le visualizzazioni fuori schermo verranno recuperate e rilasciate su avviso di memoria, ma la vista su schermo non verrà rilasciata & # 8211; è visibile e necessario. Nel caso in cui la tua classe possieda molta memoria, come cache, immagini o simili, [super didReceiveMemoryWarning]; è dove dovresti eliminarli, anche se sono sullo schermo; in caso contrario, l'app potrebbe essere terminata per aver bloccato le risorse di sistema. È necessario ignorare questo metodo per assicurarsi di ripulire la memoria; ricorda solo di chiamare <=>.

Una spiegazione ancora più elaborata è disponibile qui: http://myok12.wordpress.com/2010/11/30/custom-uiviewcontrollers-their-views-and-their-memory-management/

Fortunatamente, il simulatore ha una comoda funzione che consente di mettere alla prova situazioni di memoria insufficiente. Inserisci alcune istruzioni NSLog () in viewDidLoad e didReceiveMemoryWarning, in questo modo: # 65532 &;

- (void)viewDidLoad {
    NSLog(@"viewDidLoad"); 
    ...
}

- (void)didReceiveMemoryWarning {
    NSLog(@"didReceiveMemoryWarning");
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top