2010-07-07 11 views
9

J'ai un contrôleur de navigation. L'une des vues ajoute des sous-vues personnalisées dans son viewDidAppear:. Je remarque que la première fois que je navigue vers une instance de ce contrôleur de vue après le lancement de l'application, viewDidAppear: invoque deux fois. Si j'ouvre cette vue de la pile et y retourne, viewDidAppear: invoque seulement une fois par apparence. Toutes les apparences suivantes invoquent viewDidAppear: une fois. Le problème pour moi est que la première fois que j'arrive à cette vue, je me retrouve avec deux fois le nombre de sous-vues. Je contourne ce problème en introduisant une variable de drapeau ou un tel, mais j'aimerais comprendre ce qui se passe et comment se fait-il que j'obtienne deux invocations dans ces circonstances.viewDidAppear appelé deux fois sur la même instance, mais seulement la première fois que cette classe charge le formulaire NIB

Répondre

14

Vous ne devez jamais compter sur -viewWillAppear:/-viewDidAppear: étant appelé de manière appropriée équilibrée avec les variantes disparaissent. Bien que les contrôleurs de vue du système fassent de leur mieux pour bien encadrer les appels correctement, je ne sais pas s'ils les garantissent, et certainement lorsque vous utilisez des contrôleurs de vue personnalisés, vous pouvez trouver des situations où ils peuvent être appelés plusieurs fois. En résumé, vos méthodes -viewWillAppear:/-viewDidAppear: doivent être idempotentes, ce qui signifie que si -viewDidAppear: est appelé deux fois de suite sur votre contrôleur, il doit se comporter correctement. Si vous souhaitez charger des vues personnalisées, vous pouvez le faire dans -viewDidLoad à la place et ensuite simplement mettre l'écran (si ce n'est déjà fait) dans -viewDidAppear:.

Vous pouvez également mettre un point d'arrêt dans votre méthode -viewDidAppear: pour voir pourquoi il est appelé deux fois la première fois qu'il apparaît.

+0

J'ai un point d'arrêt dans 'viewDidAppear:'. Comment peut-il répondre à la question pourquoi? – iter

+0

Examinez la trace de la pile pour savoir pourquoi le système appelle cette méthode. Si le backtrace est différent pour les deux appels, vous pouvez l'utiliser pour essayer de comprendre ce qui se passe. Cela peut ou peut ne pas être utile, en fonction précisément de ce qui est contenu dans le backtrace. –

+0

Les piles semblent identiques, d'où ma surprise à votre suggestion. Ma solution est de refactoriser le code afin que je puisse appeler le code dans 'viewDidAppear:' indirectement à partir de 'viewDidLoad:', et éviter ainsi tout le problème. J'accepte votre réponse même si la double invocation est toujours un mystère pour moi. – iter

1

peut-être vous appelez viewDidAppear dans viewDidLoad (ou d'autres choses se passe là-bas), car il est appelé une seule fois lors du chargement de la vue de la mémoire. Il correspondrait, qu'il est invoqué deux fois seulement la première fois.

+0

Ce fut ma première pensée. Mais non, je ne fais pas ça. Et si je mets un point d'arrêt pour voir l'invocation de 'viewDidAppear:', aucune de mes méthodes n'apparaît dedans. – iter

0

Vous devriez certainement fournir plus d'informations.

Est-ce le contrôleur de vue racine?
Peut-être que vous initiez le contrôleur de navigation avec ce contrôleur de vue racine, puis le repoussez sur le contrôleur de navigation?

+0

Idée intéressante, mais non, je ne la pousse pas deux fois. Je 'NSLog (@"% @ ", [[self navigationController] viewControllers]);' from 'viewDidAppear' et voir une instance de ma vue en haut de la vue racine. – iter

+0

Peut-être avez-vous deux contrôleurs de navigation par erreur? –

0

Une autre solution qui peut avoir été votre cause sous-jacente: Assurez-vous de ne pas présenter de nouveaux contrôleurs de vue à partir de votre méthode viewWillAppear:.

j'appelle:

[appDel.window.rootViewController presentViewController:login animated:YES completion:nil]; 

à l'intérieur viewWillAppear et de voir mon origine méthode VC viewDidAppear: appelé deux fois successivement avec la même trace de la pile que vous mentionnez.Et aucun appel intermédiaire à viewDidDisappear:

Moving presentViewController: à ORIGINAIRE méthode VC viewDidAppear: éclairci la question de la double appel, et maintenant le flux est:

  1. originale viewDidAppear: appelé
    • Appel presentViewController ici
  2. Original viewDidDisappear: appelé
  3. Nouvelle vue est présentée et ne me donne un avertissement sur "unbalanced VC display"

fixe avec l'aide de cette réponse: https://stackoverflow.com/a/13315360/1143123 tout en essayant de résoudre "Unbalanced calls to begin/end appearance transitions for ..."

-1

c'est un problème ennuyeux, on pourrait penser qu'il fonctionne une fois mais alors je découvre maintenant à propos de ce qui cause le chaos ... Cela s'applique à tous 3 (ViewDidAppear, ViewDidLoad et ViewWillAppear), je reçois ceci lors de l'intégration avec un terminal de paiement; Une fois l'API terminée, la fenêtre est en train d'être rechargée quand elle est déjà à l'écran et toute sa mémoire est toujours là (non conservée).

Je résolus en procédant comme suit à toutes les routines mentionnées ci-dessus, au-dessous est un échantillon à l'un d'entre eux:

BOOL viewDidLoadProcessed = false; 

-(void)viewDidLoad:(BOOL)animated 
{ 
    if (!viewDidLoadProcessed) 
    { 
     viewDidLoadProcessed = YES; 
     . 
     . 
     . 
     ... do stuff here... 
     . 
     . 
    } 
} 

Répétez ce qui précède pour tous les deux autres, ce qu'il empêche de courir deux fois. Cela ne s'est jamais produit avant que Steve Jobs ne meure !!!

Cordialement Heider Sati

1

Si vous avez une ligne comme celui-ci dans votre AppDelegate

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

assurez-vous que vous ne possédez pas une propriété « nom de base de fichier nib principal » dans votre plist défini sur "Window.xib" ou quel que soit le nom de votre plume de fenêtre personnalisée. Si vous le faites, retirez cette ligne de votre plist et assurez-vous quelque chose comme

yourRootVC = [[UIViewController alloc] init]; 
[window setRootViewController:yourRootVC]; 

dans votre AppDelegate après instanciation votre fenêtre. Dans la plupart des cas, vous pouvez également supprimer le fichier Window.xib en toute sécurité.

1

Ajout [super viewDidAppear:animated]; a fonctionné pour moi:

//Called twice 
- (void)viewDidAppear:(BOOL)animated{ 

} 

//Called once 
- (void)viewDidAppear:(BOOL)animated{ 
    [super viewDidAppear:animated]; 
} 
+1

En enregistrant cela, le super n'arrête pas de charger deux fois. –

Questions connexes