Frage

Wer weiß, warum diese Wurzel View Controller's viewDidLoad wird zweimal aufgerufen am Start?It ' s driving me nuts!

hier ist der stack-trace von der ersten Zeit durch 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

und das zweite mal:

#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
War es hilfreich?

Lösung

Seltsam.Ich haven ' T gesehen diesem speziellen Fall, aber im Allgemeinen sollten Sie davon ausgehen, dass viewDidLoad mehrmals aufgerufen werden kann.Werde es immer aufgerufen, wenn eine nib-Datei, die Verweise, dass der controller geladen wird.

Für eine einfache app mit nur einer Spitze, das sollte nicht passieren.Aber in einer komplexen app, laden und entladen von view-Controllern, dies geschieht die ganze Zeit.

Andere Tipps

Ich hatte das gleiche Problem, wenn meine app wurde erstmals starten.Was ich fand, war, dass in meiner MainWindow.xib-Datei, ich war Einstellung, sowohl auf meinem App-Delegaten viewController Steckdose, und mein Fenster ist rootViewController Steckdose, um mein root-view-controller.Wenn Sie erstellen eine Ansicht Basierend Projekt-Datei in Xcode, Ihren App-Delegaten didFinishLaunchingWithOptions vorab ausgefüllt werden mit:

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

Ich glaube, dass die self.viewController ivar instanziiert wird von MainWindow.xib vor didFinishLaunchingWithOptions aufgerufen wird.Dann wird der voreingestellte code oben setzt das Fenster rootViewController.Also, wenn in Verbindung, geben Sie die rootViewController Steckdose für die Fenster in Ihrem MainWindow.xib-Datei, die Ihr root-view-controller tatsächlich zweimal angelegt werden und Hinzugefügt, als das Fenster root-view-controller, zwei mal.

Ich habe einige debugging und hier ist was ich gefunden habe über die ViewController Ladereihenfolge:

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

Während der loadView-Methode, initWithCoder: genannt wird und sich eine neue Kopie der viewController erstellt wird.dies ist, was übergeben wird, in ein paar Methoden (wie viewDidLoad).die Kopie wird zerstört, später in einem dealloc nennen.die gute Nachricht ist, dass Sie in diesem kopieren, beibehalten outlets sind nicht konfiguriert, so können Sie dies als einen test, um zu wissen, wenn sollte man Variablen initialisieren, rufen andere Methoden, und vor allem, wenn Sie frei und zerstören Sie Objekte in der dealloc.

Hauptaussage:die echte viewController haben wird beibehalten IBOutlet Eigenschaften konfiguriert.wenn Sie in eine überschriebene Methode, die immer namens mehrmals, überprüfen Sie einfach eines Ihrer beibehalten IBOutlet Eigenschaften NULL.wenn Sie NULL, dann sofort wieder zurück.

Hat jemand eine Idee, warum dies geschieht auf diese Weise?

Nebeneffekt:Sie können nicht verwenden awakeFromNib zuverlässig.

Sie können nicht davon ausgehen viewDidLoad wird nur einmal aufgerufen werden.Wenn Sie die Initialisierung von Objekten und wollen eine Garantie tun die Initialisierung entweder in der init-Methode oder, wenn Sie das laden aus einer nib-Datei aus der awakeFromNib-Methode.

Ich hatte ein ähnliches problem und es war ein Ergebnis der Umbenennung meiner XIB-Datei, und seine ViewController Klasse (Datei-Besitzer).Tun Sie das nicht-wie es wirklich den Blick und Delegierten misdefined innerhalb der XML-und es war nicht erstattungsfähig.Inzwischen hatte ich einen Verweis auf das laden der ursprünglichen VC das war ja auch meine neue VC.Ich glaube, dass verursacht die Eltern reproduzieren sich selbst und dann die VC war ich wirklich versucht, zu rufen.Im Grunde habe ich eine indirekte Rekursion für die VC hat x2 viewDidLoad Einträge in meine Spur.

Ich glaube nicht, dass es keinen stichhaltigen Grund für x2 viewDidLoad wie es ist, eine genesis und aufrufen können andere Initialisierung mit dem falschen angenommen pre-Bedingungen.Jedes mal, wenn ich gesehen habe das x2 viewDidLoad, es wurde ein Codierungsfehler auf mein Teil -- ziemlich oft, wenn ich war das refactoring und beweglichen VC-Klassen um.

Wenn es keinen triftigen Grund mehr als auf viewDidLoad rufen Sie, bitte jemanden (Apple Dev hören Sie) erkläre es in technischen Details -- ich habe die Suche für Antworten jetzt schon seit Monaten.

Ich hatte dieses problem aber war in der Lage, es zu beheben.

Lösung:

Benennen Sie die view-controller-Klasse, die laden zweimal.

Details:

Benennen Sie es und machen Sie den neuen Namen etwas völlig neues. Umbenennen der Datei nicht zu stoppen die Last-doppelt-Problem.Ein neues Projekt erstellen (wie vorgeschlagen, die von anderen) möglicherweise zu viel des guten, zumindest versuchen Sie die einfachere Lösungen zuerst!Benennen Sie die Klasse der Ziel-VC.

Hinweis:Wenn die Umbenennung der Klasse behebt Ihr Problem, Sie dann natürlich aktualisiert alle Verweise auf diese Klasse.Sie können diese Fahrt durch die Verwendung von Befehl+Umschalt+F für das Gesamtprojekt zu finden.

Ich lief in das gleiche problem wie ich war die Neugestaltung einer ViewController von Grund auf neu, um loszuwerden, der XIB-Datei und die Klasse wiederverwendbar.Ich hatte diese zweite ViewController Instanz, die erhalten würde, ein viewDidLoad Nachricht gefolgt von einer dealloc Nachricht.

Ich fand heraus, dies war das Ergebnis der loadView Methode nicht neu definiert, in der ViewController.Die Standard - loadView genannt awakeFromNib, mit der nibName - Eigenschaft auf den Namen der Klasse.Obwohl ich entfernt hatte, die XIB-Datei aus dem Projekt, es wurde noch in dem Verzeichnis der Anwendung auf dem simulator.

So, obwohl, Sie könnten nur zurücksetzen, Inhalte und Einstellungen des Simulators, um loszuwerden, die zweite viewDidLoad, ein besserer Weg könnte sein, einfach neu definieren loadView wie diese:

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

Es macht Sinn, wenn Sie die Dokumentation für die UIViewController's view-Eigenschaft:

Wenn Sie Zugriff auf diese Eigenschaft und seine Wert derzeit nil, Ansicht Controllers ruft automatisch die loadView Methode und gibt die resultierende Ansicht.Die Standard - loadView Methode versucht, das laden der Ansicht aus die nib-Datei mit der zugehörigen Ansicht controller (falls vorhanden).Wenn Sie Ihre Ansicht controller nicht über einen zugeordneten nib-Datei, die Sie überschreiben sollten, die loadView Methode und verwenden Sie es zu schaffen die stammansicht und alle Ihre Unteransichten.

In meinem Fall, habe ich nicht bemerkt, dass ich tatsächlich zugewiesen rootViewController zweimal:

application:didFinishLaunchingWithOptions: und applicationDidBecomeActive:

Nur zu ergänzen, wenn Sie eine system-Funktion, wie TouchID, dann applicationWillResignActive in Ihrem AppDelegate bekommen wird aufgerufen, und wenn Sie sagen, zurücksetzen auf Controller, um ein Sicheres Root-Controller dann erhalten Sie reinvoked, und performSegueWithIdentifier(self.MAIN_SEGUE ,Absender:selbst) nicht zünden!

Dies geschah zu mir, wenn ich fügte ein Projekt vom storyboard auf die alte Weise mit xibs für die Konstruktion von Ansichten.Der Hauptgrund für den Wechsel zurück, war die Tatsache, ich konnte nicht richtig gesetzt, eine modale Ansicht richtig.Die Art, wie ich normalerweise tun, ist es, durch eine delegate-Methode von einem UIButton erstellen Sie eine Instanz einer bestimmten viewcontroller, setzen Sie einige seiner Eigenschaften (die meisten import ist eine Stellvertretung, so kann ich richtig schließen des modalen view-controller wieder) und dann in einem modalen Weg.In der neuen storyboard Art, das ist angeblich mit einem segue.Anpassen der übergang ist nur machbar, indem Sie eine benutzerdefinierte Klasse, die erweitert die UIStoryboardSegue Klasse.Ich finde das viel zu viel Aufwand im Vergleich zu den einfachen Weg es verwendet zu sein, damit ich wieder zusammengeführt.

Wie hat diese Sache, die mich viewcontroller Last zweimal?Bei der übertragung des Codes von der storyboard-Projekt, um die xib Projekt, ich habe ein paar xibs (eine für jeden ViewController) und kopiert das viewcontroller-Objekt aus dem storyboard.Dies führte zu einer xib-mit es nicht zu einer viw, aber ein viewcontroller;das heißt, ich hatte einen viewcontroller in einem viewcontroller (da der Besitzer der Datei ist auch eine Instanz von viewcontroller).Ich glaube nicht, dass in Ihrem Fall, dass Sie dieses problem hatte, aber ich hoffe, dass es vielleicht jemandem hilft, irgendwann.

Um dies zu beheben, bewegen Sie die Aussicht von den view-controller aus der view-controller und auf die root-Ebene der Objekte Abschnitt.Sowohl die view-controller und ist es in der navigation den Punkt gelöscht werden soll.Erstellen und ausführen, und Sie sollten sehen, nur eine Zuordnung, die für die view-controller.Dieser ist der Besitzer der Datei.

Was ist, wenn Ihr code hat Zugriff auf die view-Eigenschaft, wenn es noch nicht geladen ist, wird der view-controller erstellen, werden nur mit leeren Blick und das auslösen könnte view did load versehentlich.

Häufigste Fehler ist der Zugriff auf view-Eigenschaft bei der Initialisierung.Möglicherweise werden einige accessor-Eigenschaft (- setter), der aufgerufen wird, von xib-Zugriff auf view-Eigenschaft versehen.

Was, wenn manche Eigenschaft versehen mit IBInspectable Sie sollten überprüfen, isViewLoaded vor einigen Wert anzeigen.


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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top