2009-06-02 6 views
12

J'ai rencontré une situation qui semble indiquer le contraire. Dans l'extrait de code suivant, si je supprime la ligne: self.navigationController = nav, la vue du contrôleur racine ne s'affichera pas, ce qui me suggère que addSubview ne peut pas conserver la vue comme suggéré autrement. Une idée?Est-ce que addSubview de UIView conserve vraiment la vue?

- (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

Votre réponse marquée n'est pas correcte, pour les raisons que j'ai commentées ci-dessous. –

Répondre

24

Cette ligne:

[window addSubview:nav.view]; 

n'ajoute une vue à l'écran immédiatement. Il est affiché par l'OS dans une boucle d'exécution future sur un thread éventuellement différent. La mise en œuvre réelle, nous ne pouvons pas être sûrs de. C'est pourquoi Apple définit des méthodes déléguées comme viewDidAppear/viewWillAppear, sinon nous n'en aurions pas besoin car nous saurions précisément quand ces événements se produisent.

En outre, l'ajout d'une sous-vue, comme vous l'avez dit, conserve effectivement la vue. Il ne pas cependant conserver le contrôleur de vue ou le contrôleur de navigation. Depuis le contrôleur de navigation va conserver les contrôleurs de vue ajouté, nous ne devons pas les sauvegarder avec un ivar. Mais, votre référence au contrôleur de navigation doit persister au-delà de la portée de la méthode. ou en fonction de votre code, il pourrait être désengagé ou avoir perdu sa référence.

Vous devez donc conserver une référence au contrôleur de navigation avec un Ivar et le mettre comme ceci:

self.navigationController = nav; 

Ainsi, même si nav.view contient un pointeur vers testViewController.view, l'application n'a pas de référence de la contrôleur de navigation et, par extension, la vue. Le résultat est un écran vide.


Pour rendre cela plus évident que ce n'est pas retenir/problème de libération, vous traces de fuites en fait dans la méthode suivante:

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

Vous devez AutoRelease pour équilibrer vos retenir/communiqués par:

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

donc, cela signifie que votre point de vue n'a jamais, jamais été désallouée chaque fois que vous avez couru ce code. Ce qui nous assure en outre que votre problème est en effet une référence perdue.

+0

Beau travail Corey, vraiment comme l'explication que vous avez exposée. – Boon

+1

Il est incorrect que le _view_ sera libéré avant que la fenêtre ne le conserve. Si tel était le cas, vous verriez une exception lorsque la fenêtre tente d'accéder à l'objet désalloué. Ce qui est désalloué, c'est le contrôleur de navigation, qui l'empêche de remplir sa vue avec du contenu intéressant (comme la barre de navigation et la vue racine). –

+0

Après y avoir pensé plus j'ai ajouté quelques infos supplémentaires qui aident aussi à expliquer ce que vous voyez. –

0

Cela ne ressemble pas à une question de conservation/publication. Vous affichez ne sera pas affiché si vous commentez self.navigationController = nav; car alors dans la ligne suivante, [window addSubview:self.navigationController.view] votre propriété self.navigationController ne sera pas réglée. Il est probablement nul ou il tomberait en panne mais ne peut pas dire avec certitude sans plus de code.

+0

J'ai remis à jour le code au code d'origine lorsque les choses ne fonctionnaient pas et j'ai dû introduire self.navigationController dans des choses pour contenir une référence à nav. En outre, ce que vous voyez ci-dessus est tout le code qu'il y a et rien d'autre. – Boon

+0

Dans l'objectif-c, les ivars commencent avec la valeur 0. Ainsi, self.navigationController serait simplement nul. –

2

Le problème n'est probablement pas que la vue n'est pas conservée, c'est que le contrôleur n'est pas conservé.

Sans cette ligne:

self.navigationController = nav 

Rien ne retient le contrôleur de navigation. Il serait étrange que la vue survive au contrôleur.

+0

Une vue n'est pas "magiquement" liée à un contrôleur de vue. Une vue ne meurt pas simplement parce que son contrôleur de vue meurt. Si la vue a été conservée ailleurs, elle survivra à tous les contrôleurs de vue. –

+0

Je n'ai pas dit que ça n'arriverait pas. J'ai dit qu'il serait étrange que l'un survive à l'autre. Particulièrement lorsque la vue est la vue du contrôleur de navigation, c'est-à-dire une hiérarchie de vue interne consignée par le contrôleur de navigation. –

+0

Si vous suivez la convention, vous avez raison. Mon seul point est que ce n'est pas une raison en soi. La seule raison pour laquelle cela a tendance à être vrai est que vous ne libérez généralement pas un contrôleur de vue avant de supprimer sa vue de la hiérarchie de vue. Mais il n'y a pas de mécanisme dans UIViewController pour vous empêcher de faire cela, il vient juste de la pratique de la gestion de la mémoire. –