Domanda

Chiunque sa perché questo View Controller's radice viewDidLoad viene chiamato due volte al momento del lancio? Mi sta facendo impazzire!

ecco la traccia dello stack da 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
È stato utile?

Soluzione

Strano. Non ho visto questo caso particolare, ma in generale, si dovrebbe presumere che viewDidLoad può essere chiamato più volte. Si otterrà chiamato ogni volta che un file nib che fa riferimento a tale controller viene caricato.

Per una semplice applicazione con un solo pennino, che non dovrebbe accadere. Ma in un'applicazione più complesso che può caricare e scaricare vista controllori, questo accade tutto il tempo.

Altri suggerimenti

Ho avuto questo stesso problema quando la mia applicazione è stato il primo lancio. Quello che ho trovato è che nel mio file MainWindow.xib, stavo installando sia il mio sfogo viewController App Delegato, e la presa di rootViewController mia finestra al mio controller della vista root. Quando si crea una vista basata file di progetto in Xcode, didFinishLaunchingWithOptions del vostro App Delegato sarà pre-popolato con:

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

Credo che l'Ivar self.viewController viene creata un'istanza da MainWindow.xib prima didFinishLaunchingWithOptions viene chiamato. Quindi il codice pre-popolato sopra imposta rootViewController della finestra. Quindi, se, in concomitanza, si specifica l'uscita rootViewController per la finestra nel file MainWindow.xib, il controller vista principale sarà effettivamente creato due volte e ha aggiunto come controller della vista principale del Window due volte.

Ho fatto un po 'di debug ed ecco cosa ho trovato circa l'ordine ViewController carico:

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

Durante il metodo loadview, initWithCoder: si chiama e viene creata una nuova copia del viewController. questo è ciò che è passato in alcuni dei metodi (come viewDidLoad). la copia viene distrutta in seguito a una chiamata dealloc. la buona notizia è che in questa copia, mantenuti punti vendita non sono configurati, in modo da poter utilizzare questo come un test per sapere se si deve inizializzare le variabili, chiamare altri metodi, e, soprattutto, se si deve liberare e distruggere oggetti durante dealloc.

asporto chiave: il vero viewController avrà le sue proprietà IBOutlet trattenuti configurati. se si è in un metodo di override che sta ottenendo chiamato più volte, basta controllare uno dei vostri immobili IBOutlet trattenuti per NULL. se sono NULL, per poi tornare immediatamente.

Qualcuno ha qualche indizio sul motivo per cui questo sta accadendo in questo modo?

effetto collaterale di questo: non è possibile utilizzare in modo affidabile awakeFromNib

.

Non si può assumere viewDidLoad sarà chiamato solo una volta. Se si sta inizializzazione degli oggetti e si desidera una garanzia di fare l'inizializzazione sia nel metodo init o se si sta caricando da un file pennino dal metodo awakeFromNib.

Ho avuto un problema simile ed è stato un risultato di rinominare il mio file XIB e la sua classe ViewController (File Proprietario). Non farlo - come in realtà ottenuto i punti di vista e dei delegati misdefined all'interno del XML e non era recuperabile. Nel frattempo, ho avuto un riferimento al carico VC originale che doveva essere il mio nuovo VC. Credo che ha causato il genitore di ricreare se stesso e poi il VC mi ha davvero cercato di richiamare. Fondamentalmente, ho creato una ricorsione indiretto al VC che ha le voci viewDidLoad x2 nella mia traccia.

Non credo che ci sia alcun motivo valido per x2 viewDidLoad in quanto è una genesi e può invocare altri l'inizializzazione con il male ha assunto pre-condizioni. Ogni volta che ho visto il viewDidLoad x2, si trattava di un errore di codifica da parte mia - molto spesso quando ero refactoring e spostando le classi VC intorno

.

Se c'è un motivo valido per più di su chiamata viewDidLoad, per favore qualcuno (Apple Dev stai ascoltando) spiegare in dettaglio tecnico -. Sono stato alla ricerca di quella risposta da mesi

Ho avuto questo problema, ma è stato in grado di risolvere il problema.

Soluzione :

Rinominare la classe di controller della vista che sta caricando due volte.

Dettagli :

Rinomina e fare il nuovo nome di qualcosa di completamente nuovo. Rinominare il file non si ferma il problema del carico-due volte. Creazione di un nuovo progetto (come suggerito da altri) potrebbe essere eccessivo, almeno provare le soluzioni più semplici in primo luogo! Rinominare la classe di destinazione VC.

Suggerimento : Se rinominare la classe risolve il problema, è poi, ovviamente, è necessario aggiornare tutti i riferimenti a tale classe. È possibile accelerare questo utilizzando Command + Shift + F per trovare a livello di progetto.

Ho incontrato lo stesso problema come mi è stato ridisegnare un ViewController da zero per sbarazzarsi del file XIB e per rendere la classe riutilizzabile. Ho avuto questa seconda istanza ViewController che avrebbe ricevuto un messaggio viewDidLoad seguito da un messaggio dealloc.

ho scoperto che questo è stato il risultato del metodo loadView non essere ridefinito nel ViewController. Il loadView predefinito chiamato awakeFromNib, con la proprietà nibName impostata al nome della classe. Anche se avevo rimosso il file XIB dal progetto, era ancora nella directory dell'applicazione sul simulatore.

Quindi, anche se si può solo ripristinare i contenuti e le impostazioni del simulatore di sbarazzarsi del secondo viewDidLoad, un modo migliore potrebbe essere quella di ridefinire proprio loadView in 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 proprietà vista UIViewController's:

  

Se si accede a questa proprietà e la sua   valore è attualmente nullo, la vista   controllore chiama automaticamente la   Metodo loadView e restituisce il   risultante vista. Il loadView di default   metodo tenta di caricare la visualizzazione da   il file nib associato alla visualizzazione   controllore (se presenti). Se la vista   controllore non ha un associato   file nib, si dovrebbe ignorare il   Metodo loadView e usarlo per creare   la vista radice e tutti i suoi subviews.

Nel mio caso, non ho notato che ho effettivamente assegnato il RootViewController due volte in:

application:didFinishLaunchingWithOptions: e applicationDidBecomeActive:

Giusto per aggiungere a questo, se si utilizza una funzione di sistema, come ad esempio TouchID, quindi applicationWillResignActive nella vostra AppDelegate otterrà invocata e se si dice, il ripristino controller a un controller di Root sicura poi si arriva rievocato, e performSegueWithIdentifier (self.MAIN_SEGUE, mittente: auto)! non viene attivato

Questo è successo a me quando ho fuso di un progetto dallo storyboard alla vecchia maniera con xibs per la costruzione di vista. La ragione principale per la commutazione di nuovo è stato il fatto non ho potuto correttamente mettere in su una vista modale correttamente. Il modo di solito è di avere un metodo delegato da un UIButton costruire un'istanza di un certo viewcontroller, impostare alcune delle sue proprietà (il più importazione uno essendo delegato modo da posso correttamente respingere nuovamente il controller di vista modale) e poi presenti in modo modale. Nel nuovo modo storyboard, questo è presumibilmente fatto con un segue. Personalizzare la transizione è fattibile solo facendo una classe personalizzata che estende la classe UIStoryboardSegue. Trovo questo modo troppo fastidio rispetto al modo semplice di una volta così ho unito di nuovo.

Come ha fatto questo causare me avere un carico viewcontroller due volte? Quando si trasferisce il codice dal progetto storyboard al progetto XIb, feci un paio di xibs (uno per ogni ViewController) e copia l'oggetto viewcontroller dallo storyboard. Ciò ha portato ad una XI ter con in esso non un viw, ma un viewcontroller; il che significa avevo messo un viewcontroller in un viewcontroller (in quanto proprietario del file è anche un'istanza della viewcontroller). Non credo che nel tuo caso che hai avuto questo problema, ma spero che forse aiuta qualcuno un giorno.

Per risolvere questo spostare la vista dal controllore vista dal controller della vista e al livello principale della sezione oggetti. Sia il controller della vista e della voce di navigazione devono essere cancellati. Costruire e gestire e si dovrebbe vedere solo un'assegnazione per il controller della vista. Questo è il proprietario del file.

Che cosa succede se il codice ha accedere alla proprietà vista quando non è ancora caricato, il controller della vista creerà solo vista vuota e potrebbe innescare view did load accidentalmente.

errore più comune è accede finestra delle proprietà durante l'inizializzazione. Può essere un po 'di accesso di proprietà (setter) che viene richiamato dal XI ter dovrebbe accedere alla visualizzazione di proprietà accidentalmente.

Che cosa succede se un po 'di proprietà è annotato con IBInspectable si dovrebbe avere per controllare isViewLoaded prima di applicare un po' il valore da visualizzare.


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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top