Question

Quelqu'un sait pourquoi cette View Controller's racine viewDidLoad est appelé deux fois au lancement? Ça me rend fou!

voici la trace de la pile de première fois par viewDidLoad:

#0  0x0000276a in -[RootViewController viewDidLoad] at RootViewController.m:71
#1  0x3097548f in -[UIViewController view]
#2  0x00002734 in -[RootViewController initWithCoder:] at RootViewController.m:39
#3  0x30ab5ce4 in -[UIClassSwapper initWithCoder:]
#4  0x30514636 in _decodeObjectBinary
#5  0x30514035 in _decodeObject
#6  0x30ab5a1d in -[UIRuntimeConnection initWithCoder:]
#7  0x30514636 in _decodeObjectBinary
#8  0x30515f27 in -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:]
#9  0x305163b0 in -[NSArray(NSArray) initWithCoder:]
#10 0x30514636 in _decodeObjectBinary
#11 0x30514035 in _decodeObject
#12 0x30ab4dde in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:]
#13 0x30ab6eb3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:]
#14 0x308f85f1 in -[UIApplication _loadMainNibFile]
#15 0x30901a15 in -[UIApplication _runWithURL:sourceBundleID:]
#16 0x308fef33 in -[UIApplication handleEvent:withNewEvent:]
#17 0x308fad82 in -[UIApplication sendEvent:]
#18 0x309013e1 in _UIApplicationHandleEvent
#19 0x32046375 in PurpleEventCallback
#20 0x30245560 in CFRunLoopRunSpecific
#21 0x30244628 in CFRunLoopRunInMode
#22 0x308f930d in -[UIApplication _run]
#23 0x309021ee in UIApplicationMain
#24 0x000022e4 in main at main.m:14

et la deuxième fois:

#0  0x0000276a in -[RootViewController viewDidLoad] at RootViewController.m:71
#1  0x30ab50cd in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:]
#2  0x30ab6eb3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:]
#3  0x308f85f1 in -[UIApplication _loadMainNibFile]
#4  0x30901a15 in -[UIApplication _runWithURL:sourceBundleID:]
#5  0x308fef33 in -[UIApplication handleEvent:withNewEvent:]
#6  0x308fad82 in -[UIApplication sendEvent:]
#7  0x309013e1 in _UIApplicationHandleEvent
#8  0x32046375 in PurpleEventCallback
#9  0x30245560 in CFRunLoopRunSpecific
#10 0x30244628 in CFRunLoopRunInMode
#11 0x308f930d in -[UIApplication _run]
#12 0x309021ee in UIApplicationMain
#13 0x000022e4 in main at main.m:14
Était-ce utile?

La solution

Bizarre

. Je ne l'ai pas vu ce cas particulier, mais en général, vous devez supposer que viewDidLoad peut être appelé plusieurs fois. Il va s'appeler chaque fois qu'un fichier nib qui fait référence à ce contrôleur se charge.

Pour une application simple avec une seule pointe, cela ne devrait pas se produire. Mais dans une application plus complexe qui peut charger et décharger les contrôleurs de vue, cela arrive tout le temps.

Autres conseils

J'ai eu ce même problème lorsque mon application a été le premier lancement. Ce que j'ai trouvé que dans mon dossier de MainWindow.xib, je mettais à la fois mon prise viewController App de délégué, et mon prise rootViewController de la fenêtre de mon contrôleur de vue racine. Lorsque vous créez un fichier de projet Voir Basé à Xcode, votre didFinishLaunchingWithOptions App délégué sera pré-remplie avec:

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;

Je crois que le Ivar de self.viewController est instancié de MainWindow.xib avant didFinishLaunchingWithOptions est appelée. Ensuite, le code préchargées fixe au-dessus de rootViewController de Windows. Donc, si, en même temps, vous spécifiez la sortie de rootViewController pour la fenêtre dans votre fichier MainWindow.xib, votre contrôleur de vue racine sera réellement créé deux fois et ajouté en tant que contrôleur de vue racine deux fois de la fenêtre.

Je l'ai fait une mise au point et voici ce que j'ai trouvé de l'ordre de chargement ViewController:

initWithNibName:bundle:     self = <original instance>, retainedOutlet = 0x0  
loadView >>>                self = <original instance>, retainedOutlet = 0x0  
      initWithCoder:        self = <coder instance>,    retainedOutlet = 0x0  
      initWithCoder:        self = <coder instance>,    retainedOutlet = 0x0  
      setView:              self = <original instance>, retainedOutlet = 0x0  
      setRetainedOutlet:    self = <original instance>, retainedOutlet = 0x1613c40  
      viewDidLoad           self = <coder instance>,    retainedOutlet = 0x0  
      awakeFromNib          self = <coder instance>,    retainedOutlet = 0x0  
loadView <<<  
viewDidLoad                 self = <original instance>, retainedOutlet = 0x1613c40  
viewWillAppear:             self = <original instance>, retainedOutlet = 0x1613c40  
dealloc                     self = <coder instance>,    retainedOutlet = 0x0
viewDidAppear:              self = <original instance>, retainedOutlet = 0x1613c40

Au cours de la méthode loadview, initWithCoder: est appelé et une nouvelle copie du viewController est créé. c'est ce qui est passé dans quelques-unes des méthodes (comme viewDidLoad). la copie est détruite plus tard dans un appel dealloc. les bonnes nouvelles sont que cette copie, conservés points de vente ne sont pas configurés, de sorte que vous pouvez l'utiliser comme un test pour savoir si vous devez initialiser les variables, appeler d'autres méthodes, et surtout, si vous devez libérer et détruire des objets pendant dealloc.

A emporter Key: le vrai viewController aura ses propriétés IBOutlet retenues configurées. si vous êtes dans une méthode surchargée qui devient appelée plusieurs fois, il suffit de cocher l'une de vos propriétés IBOutlet retenues pour NULL. si elles sont NULL, puis revenez immédiatement.

Quelqu'un a des indices pour expliquer pourquoi cela se passe de cette façon?

L'effet secondaire de ceci, vous ne pouvez pas utiliser awakeFromNib fiable

.

Vous ne pouvez pas supposer viewDidLoad sera appelée une seule fois. Si vous initialisez objets et que vous voulez faire une garantie de l'initialisation soit dans la méthode d'initialisation ou si vous chargez d'un fichier nib de la méthode awakeFromNib.

J'ai eu un problème similaire et il est le résultat de renommer mon fichier et sa classe XIB de ViewController (propriétaire du fichier). Ne pas le faire - comme il vraiment obtenu les vues et les délégués à l'intérieur du XML mal défini et il n'a pas été recouvrable. Pendant ce temps, j'avais une référence à la charge du VC d'origine qui était censé être mon nouveau VC. Je crois que le parent fait de se recréer et le VC je suis vraiment tenté d'invoquer. En fait, j'ai créé une récursion indirecte à la VC qui a x2 entrées viewDidLoad dans ma trace.

Je ne pense pas qu'il y ait une raison valable pour viewDidLoad x2 comme il est une genèse et peut invoquer d'autres initialisations avec la mauvaise suppose des conditions préalables. Chaque fois que je l'ai vu le viewDidLoad x2, ce fut une erreur de codage de ma part - très souvent quand je refactoring et le déplacement des classes VC autour

.

S'il y a une raison valable pour plus que sur appel viewDidLoad, s'il vous plaît quelqu'un (Apple Dev-vous écoute) expliquer en détail technique -. Je cherchais cette réponse depuis des mois

J'ai eu ce problème, mais a été en mesure de le réparer.

Solution :

Renommer la vue classe contrôleur qui charge deux fois.

Détails :

renommer et de faire le nouveau nom quelque chose d'entièrement nouveau. renommant le fichier n'arrête pas le problème de charge deux fois. Création d'un nouveau projet (comme suggéré par d'autres) pourrait être surpuissant, au moins essayer les solutions plus simples d'abord! Renommer la classe de la destination VC.

Conseil : Si renommer la classe résout votre problème, vous avez alors évidemment de mettre à jour toutes vos références à cette classe. Vous pouvez accélérer ce en utilisant Commande + Maj + F pour trouver l'ensemble du projet.

Je suis tombé sur le même problème que je ViewController une refonte à partir de zéro pour se débarrasser du fichier et de faire XIB la classe réutilisable. J'ai eu cette deuxième instance ViewController qui recevra un message de viewDidLoad suivi d'un message dealloc.

J'ai découvert ce fut le résultat de la méthode loadView pas redéfini dans le ViewController. Le loadView par défaut appelé awakeFromNib, avec la propriété nibName définie sur le nom de classe. Même si j'avais enlevé le fichier du projet XIB, il était encore dans le répertoire de l'application sur le simulateur.

Ainsi, même si vous pouvez simplement réinitialiser le contenu et les paramètres du simulateur pour se débarrasser de la seconde viewDidLoad, une meilleure façon peut-être redéfinir juste loadView comme ceci:

- (void)loadView {
    self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; 
}

Il est logique si l'on considère la documentation de la propriété vue UIViewController's:

  

Si vous accédez à cette propriété et son   valeur est actuellement nulle, la vue   contrôleur appelle automatiquement la   Procédé de loadView et renvoie le   vue résultant. La valeur par défaut loadView   Procédé tente de charger la vue de   le fichier nib associé à la vue   contrôleur (le cas échéant). Si votre vue   contrôleur ne dispose pas d'un associé   fichier nib, vous devez remplacer le   méthode loadView et l'utiliser pour créer   la vue racine et tous ses sous-vues.

Dans mon cas, je ne l'ai pas remarqué que je l'ai fait affecté la RootViewController deux fois:

application:didFinishLaunchingWithOptions: et applicationDidBecomeActive:

Il suffit d'ajouter à cela, si vous utilisez une fonction de système, comme TouchID, puis applicationWillResignActive dans votre AppDelegate va obtenir invoqué et si vous dites, la réinitialisation contrôleurs à un contrôleur sécurisé racine puis vous obtenez reinvoked et performSegueWithIdentifier (self.MAIN_SEGUE, expéditeur: auto) ne se déclenche pas

Ce qui est arrivé à moi quand je fusionné un projet du story-board à l'ancienne à l'aide xibs pour la construction de vues. La raison principale de commutation de retour était le fait que je ne pouvais pas correctement mis en place correctement une vue modale. La façon dont je le fais habituellement, il est en ayant une méthode déléguée d'un UIButton construire une instance d'un certain viewcontroller, définir certaines de ses propriétés (plus une importation étant le délégué afin que je puisse bien rejeter à nouveau le contrôleur modal vue) puis présente d'une manière modale. Dans la nouvelle façon story-board, cela est censé être fait avec un Segue. Personnalisation de la transition est seulement faisable en faisant une classe personnalisée qui étend la classe UIStoryboardSegue. Je trouve cette façon trop de problèmes par rapport à la façon simple qu'elle était donc je refusionnées.

Comment cela me causer d'avoir une charge de viewcontroller deux fois? Lors du transfert du code du projet de maquette au projet XIB, je fait quelques xibs (un pour chaque ViewController) et copié l'objet viewcontroller du story-board. Cela a conduit à un xib avec en elle pas viw, mais un viewcontroller; ce qui signifie que j'avais mis un viewcontroller dans un viewcontroller (depuis le propriétaire du fichier est également une instance de la viewcontroller). Je ne pense pas que dans votre cas que vous avez eu ce problème, mais j'espère que cela aide peut-être quelqu'un un jour.

Pour résoudre ce problème déplacer la vue du contrôleur de vue sur le contrôleur de vue et au niveau de la racine de la section des objets. Tant le contrôleur de vue et point de navigation devraient être supprimés. Générez et exécutez et vous devriez voir une seule allocation pour le contrôleur de vue. Ceci est le propriétaire du fichier.

Que faire si votre code n'accéder à la propriété de vue quand il est pas encore chargé, le contrôleur de vue crée juste vue vide et il pourrait déclencher view did load accidentellement.

erreur la plus commune est la propriété de vue accède lors de l'initialisation. Peut-être un peu accesseur propriété (setter) qui est invoquée par xib devrait accéder accidentellement la propriété de la vue.

Que faire si une propriété est annotées avec IBInspectable vous devriez avoir à vérifier avant d'appliquer isViewLoaded une valeur pour la voir.


-(void) setSomeProperty:(UIColor*) someColor
{
  _someColor = someColor;
  if(self.isViewLoaded) {
    // self.view causes view creation and invokes 'viewDidLoad' then the view is not ready yet.
    self.view.backgroundColor = someColor;
  }
}

-(void) viewDidLoad
{
  [super viewDidLoad]
  if(_someColor){
    self.view.backgroundColor = _someColor;
  }
}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top