viewDidLoad viene chiamato due volte su rootViewController all’avvio

Qualcuno sa perché View Controller's viewDidLoad questo View Controller's viewDidLoad viene chiamato due volte all’avvio? Mi sta facendo impazzire!

ecco la traccia dello stack dalla prima volta attraverso 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 

e la seconda volta:

 #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 

    Strano. Non ho visto questo caso particolare, ma in generale, dovresti assumere che viewDidLoad possa essere chiamato più volte. Viene chiamato ogni volta che viene caricato un file pennino che fa riferimento a quel controller.

    Per una semplice app con un solo pennino, ciò non dovrebbe accadere. Ma in un’app più complessa in grado di caricare e scaricare controller di visualizzazione, questo accade sempre.

    Ho avuto questo stesso problema quando la mia app è stata lanciata per la prima volta. Quello che ho trovato è che nel mio file MainWindow.xib, stavo impostando sia l’outlet del mio App Delegate viewController , sia l’uscita rootViewController della mia finestra sul mio controller di visualizzazione radice. Quando didFinishLaunchingWithOptions un file di progetto basato su vista in Xcode, il tuo delegato dell’app ha didFinishLaunchingWithOptions sarà precompilato con:

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

    Credo che il self.viewController ivar sia istanziato da MainWindow.xib prima che didFinishLaunchingWithOptions chiamataFinishLaunchingWithOptions. Quindi il codice precompilato sopra imposta il rootViewController della finestra. Quindi, se, in combinazione, si specifica l’uscita rootViewController per la finestra nel file MainWindow.xib, il controller della vista radice verrà effettivamente creato due volte e aggiunto come controller della vista radice della finestra due volte.

    Ho fatto un po ‘di debug e ecco cosa ho trovato sull’ordine di caricamento di ViewController :

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

    Durante il metodo loadView, viene chiamato initWithCoder: viene creata una nuova copia di viewController . questo è ciò che è passato in alcuni dei metodi (come viewDidLoad ). la copia viene distrutta successivamente in una chiamata dealloc. la buona notizia è che in questa copia, le prese mantenute non sono configurate, quindi puoi usare questo come test per sapere se dovresti inizializzare le variabili, chiamare altri metodi e, soprattutto, se dovessi rilasciare e distruggere oggetti durante dealloc.

    Key takeaway: il vero viewController avrà le sue proprietà IBOutlet mantenute configurate. se si è in un metodo IBOutlet a override che viene richiamato più volte, è sufficiente selezionare una delle proprietà IBOutlet mantenute per NULL . se sono NULL , quindi restituire immediatamente.

    Qualcuno ha qualche indizio sul perché questo sta accadendo in questo modo?

    Effetto collaterale di questo: non è ansible utilizzare in modo affidabile awakeFromNib .

    Non puoi assumere che viewDidLoad venga chiamato una sola volta. Se si stanno inizializzando oggetti e si desidera una garanzia, eseguire l’inizializzazione nel metodo init o se si sta caricando da un file pennino dal metodo awakeFromNib.

    Ho avuto un problema simile ed è stato il risultato della rinomina del mio file XIB e della sua class ViewController (File Owner). Non farlo – in quanto ha davvero le viste e i delegati erroneamente definiti all’interno dell’XML e non è stato recuperabile. Nel frattempo, ho avuto un riferimento al carico del VC originale che doveva essere il mio nuovo VC. Credo che abbia causato il ricominciamento del genitore e poi il VC che ho davvero cercato di invocare. Fondamentalmente, ho creato una ricorsione indiretta al VC che ha le voci x2 viewDidLoad nella mia traccia.

    Non penso ci sia alcun motivo valido per x2 viewDidLoad in quanto è una genesi e può invocare altre inizializzazioni con presupposti errati. Ogni volta che ho visto x2 viewDidLoad, è stato un errore di codifica da parte mia – molto spesso quando stavo rifacendo e spostando le classi VC in giro.

    Se c’è un motivo valido per più di viewDidLoad chiamata a viewDidLoad , per favore qualcuno (Apple Dev stai ascoltando) lo spiega nei dettagli tecnici – Ho cercato quella risposta per mesi ora.

    Ho avuto questo problema ma è stato in grado di risolverlo.

    Soluzione :

    Rinominare la class del controller della vista che viene caricata due volte.

    Dettagli :

    Rinominalo e rendi il nuovo nome qualcosa di completamente nuovo. Rinominare il file non interrompe il problema di caricamento due volte. Creare un nuovo progetto (come suggerito da altri) potrebbe essere eccessivo, almeno provare prima le soluzioni più semplici! Rinominare la class del VC di destinazione.

    Suggerimento : se la rinomina della class risolve il tuo problema, devi ovviamente aggiornare tutti i tuoi riferimenti a quella class. Puoi accelerare usando Command + Shift + F per trovare il progetto.

    Mi sono imbattuto nello stesso problema mentre stavo riprogettando un ViewController da zero per sbarazzarmi del file XIB e rendere la class riutilizzabile. Ho avuto questa seconda istanza di viewDidLoad che avrebbe ricevuto un messaggio viewDidLoad seguito da un messaggio dealloc.

    Ho scoperto che questo era il risultato del metodo loadView che non veniva ridefinito nel ViewController . loadView predefinito chiamato awakeFromNib , con la proprietà nibName impostata sul nome della class. Anche se avevo rimosso il file XIB dal progetto, era ancora nella directory dell’applicazione sul simulatore.

    Quindi, anche se puoi semplicemente ripristinare i contenuti e le impostazioni del simulatore per eliminare il secondo viewDidLoad , un modo migliore potrebbe essere quello di ridefinire loadView questo modo:

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

    Ha senso se si considera la documentazione per la UIViewController's vista UIViewController's :

    Se si accede a questa proprietà e il suo valore è attualmente nullo, il controller della vista chiama automaticamente il metodo loadView e restituisce la vista risultante. Il metodo loadView predefinito tenta di caricare la vista dal file pennino associato al controller della vista (se presente). Se il controller della vista non ha un file pennino associato, è necessario sovrascrivere il metodo loadView e utilizzarlo per creare la vista radice e tutte le sue sottoview.

    Nel mio caso, non ho notato che in realtà ho assegnato il rootViewController due volte in:

    application:didFinishLaunchingWithOptions: e applicationDidBecomeActive:

    Solo per aggiungere a questo, se si sta utilizzando una funzione di sistema, come TouchID, quindi applicationWillResignActive in AppDelegate verrà richiamato e, se si sta dicendo, reimpostando i controller su un controller radice sicuro, si verrà reinvocati e performSegueWithIdentifier (self.MAIN_SEGUE , mittente: self) non sparerà!

    Questo è successo a me quando ho unito un progetto dallo storyboard al vecchio modo usando xibs per build viste. Il motivo principale per cui ho dovuto tornare indietro era il fatto che non potevo installare correttamente una vista modale in modo corretto. Il modo in cui solitamente lo faccio avendo un metodo delegato da un UIButton costruisca un’istanza di un certo viewcontroller, imposta alcune delle sue proprietà (la maggior parte dell’importazione è il delegato, quindi posso di nuovo ignorare il controller della vista modale di nuovo) e quindi presentare in modo modale. Nel nuovo modo dello storyboard, questo è presumibilmente fatto con un seguito. La personalizzazione della transizione è ansible solo creando una class personalizzata che estenda la class UIStoryboardSegue. Trovo che sia troppo fastidioso rispetto al modo in cui un tempo era così mi sono ricomposto.

    Come mai questo mi ha fatto caricare un viewcontroller due volte? Durante il trasferimento del codice dal progetto storyboard al progetto xib, ho creato un paio di xibs (uno per ciascun ViewController) e copiato l’object viewcontroller dallo storyboard. Ciò ha portato a uno xib con in sé non un viw, ma un viewcontroller; nel senso che avevo messo un viewcontroller in un viewcontroller (dal momento che il proprietario del file è anche un’istanza del viewcontroller). Non penso nel tuo caso che tu abbia avuto questo problema ma spero che forse aiuti qualcuno un giorno.

    Per risolvere questo problema spostare la vista dal controller della vista fuori dal controller della vista e al livello principale della sezione degli oggetti. Il controller della vista e il suo elemento di navigazione devono essere eliminati. Costruisci ed esegui e dovresti vedere solo un’allocazione per il controller della vista. Questo è il proprietario del file.