2009-06-02 12 views
12

Mi sono imbattuto in una situazione che sembra suggerire il contrario. Nel seguente frammento di codice, se rimuovo la riga: self.navigationController = nav, la vista del controller di root non verrà mostrata, suggerendomi che addSubview potrebbe non mantenere la visualizzazione come suggerito altrimenti. Qualche idea?L'addSubview di UIView mantiene davvero la vista?

- (void)applicationDidFinishLaunching:(UIApplication *)application { 
    self.testViewController = [[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]]; 

    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.testViewController]; 

    self.navigationController = nav; //<-- if this line is removed, test view won't show up 

    [window addSubview:nav.view]; 

    [nav release]; 
} 
+0

La risposta contrassegnata non è corretta, per i motivi che ho commentato di seguito. –

risposta

24

Questa linea:

[window addSubview:nav.view]; 

non aggiunge una vista sullo schermo immediatamente. Viene visualizzato dal sistema operativo in qualche ciclo di esecuzione futuro su un thread probabilmente diverso. L'effettiva implementazione di cui non possiamo essere sicuri.

Questo è il motivo per cui Apple definisce metodi delegati come viewDidAppear/viewWillAppear, altrimenti non avremmo bisogno di essi come sapremmo esattamente quando si verificano questi eventi.

Inoltre, aggiungendo una sottoview come hai detto, mantiene effettivamente la vista. Lo standard NON tuttavia conserva il controller di visualizzazione o il controller di navigazione. Dato che il controller di navigazione conserverà qualsiasi controller di vista aggiunto, non è necessario eseguirne il backup con un ivar.

Tuttavia, il riferimento al controller di navigazione deve rimanere oltre l'ambito del metodo. oppure, a seconda del codice, potrebbe essere deallocato o avere perso il riferimento.

Quindi è necessario mantenere un riferimento al controller di navigazione con un Ivar e impostarlo in questo modo:

self.navigationController = nav; 

Così, anche se nav.view contiene un puntatore al testViewController.view, l'applicazione non ha alcun riferimento alla controller di navigazione e, per estensione, la vista. Il risultato è uno schermo vuoto.


per rendere questo più evidente che non è un trattenere/problema di rilascio, in realtà si sta che fuoriesce nel seguente metodo:

self.testViewController = [[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]]; 

È necessario autorelease per bilanciare le vostre mantenere/rilasci da:

self.testViewController = [[[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]] autorelease]; 

Quindi, questo significa che il punto di vista è mai, mai stato deallocato ogni volta che avete eseguito questo codice. Il che ci assicura ulteriormente che il tuo problema è davvero un riferimento perso.

+0

Bel lavoro Corey, mi piace molto la spiegazione che hai esposto. – Boon

+1

Non è corretto che _view_ venga deallocato prima che la finestra lo mantenga. Se così fosse, vedresti un'eccezione quando la finestra tenta di accedere all'oggetto deallocato. Ciò che viene deallocato è il controller nav, che impedisce di popolare la sua vista con contenuti interessanti (come la barra di navigazione e la vista root). –

+0

Dopo averci pensato di più ho aggiunto alcune informazioni aggiuntive che aiutano anche a spiegare quello che vedi. –

0

Questo non mi sembra una domanda di conservazione/rilascio per me. La visualizzazione non verrà visualizzata se si commenta self.navigationController = nav; perché nella riga successiva, [window addSubview:self.navigationController.view], la proprietà self.navigationController non verrà impostata. Probabilmente è zero o si bloccherebbe ma non si può dire per certo senza più del codice.

+0

Ho aggiornato il codice al codice originale quando le cose non hanno funzionato e ho dovuto introdurre self.navigationController in cose per contenere un riferimento a nav. Inoltre, ciò che vedi sopra è tutto il codice che c'è e nient'altro. – Boon

+0

Nell'obiettivo-c, ivars inizia con il valore 0. Quindi, self.navigationController sarebbe solo zero. –

2

Il problema probabilmente non è che la vista non viene mantenuta, è che il controller non viene mantenuto.

Senza questa linea:

self.navigationController = nav 

Nulla è trattenere il controller di navigazione. Sarebbe strano che la vista sopravviva al controller.

+0

Una vista non è "magicamente" legata a un controller di visualizzazione. Una vista non muoiono semplicemente perché il suo controller di visualizzazione muore. Se la vista è stata mantenuta altrove, sarà sicuramente sopravvissuta a qualsiasi controller di visualizzazione. –

+0

Non ho detto che non sarebbe successo. Ho detto che sarebbe strano per uno sopravvivere all'altro. Soprattutto quando la vista è la vista del controller di navigazione, che è una gerarchia di visualizzazione interna integrata dal controller di navigazione. –

+0

Se segui la convenzione, hai ragione. Il mio unico punto è che non è un motivo in sé e per sé. L'unico motivo per cui questo tende ad essere vero è perché generalmente non si rilascia un controller di visualizzazione prima di rimuovere la sua vista dalla gerarchia della vista. Ma non ci sono meccanismi in UIViewController per impedirti di farlo, ma deriva dalla pratica di una corretta gestione della memoria. –

Problemi correlati