Pregunta

Alguien sabe por qué esto View Controller's viewDidLoad raíz se llama dos veces en el lanzamiento? Me está volviendo loco!

aquí está el seguimiento de la pila de la primera vez a través 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

y la segunda vez:

#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
¿Fue útil?

Solución

extraño. No he visto a este caso en particular, pero en general, usted debe asumir que viewDidLoad puede ser llamado varias veces. Se obtendrá un archivo llamado siempre que la semilla que hace referencia a que el controlador se carga.

Para una aplicación sencilla con una sola semilla, eso no debería suceder. Sin embargo, en una aplicación más compleja que se puede cargar y descargar los controladores de vista, esto sucede todo el tiempo.

Otros consejos

Tuve este mismo problema cuando mi aplicación fue el primer lanzamiento. Lo que encontré fue que en mi archivo MainWindow.xib, yo estaba sentado tanto mi salida viewController App Delegado, y la salida rootViewController de mi ventana a mi controlador de vista raíz. Cuando se genera un archivo de proyecto Ver Basado en Xcode, didFinishLaunchingWithOptions de su aplicación Delegado será rellenada previamente con:

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

Creo que el Ivar self.viewController se crea una instancia de MainWindow.xib antes didFinishLaunchingWithOptions se llama. A continuación, el código pre-poblada anterior establece rootViewController de la ventana. Así que si, en conjunto, se especifica la salida rootViewController por la ventana en su archivo MainWindow.xib, el controlador de vista raíz será realmente crea dos veces y se agrega como controlador de vista raíz de la ventana dos veces.

He hecho un poco de depuración y esto es lo que encontré sobre el orden ViewController de carga:

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 el método loadView, initWithCoder: se llama y se crea una nueva copia de la viewController. esto es lo que se pasa en algunos de los métodos (como viewDidLoad). la copia se destruye más tarde en una llamada dealloc. la buena noticia es que en esta copia, retenidos salidas no están configurados, por lo que puede utilizar esto como una prueba para saber si debe inicializar variables, llamar a otros métodos, y lo más importante, si debe liberar y destruir objetos durante dealloc.

Conclusión clave: la verdadera viewController tendrá sus propiedades retenidas IBOutlet configurados. si se encuentra en un método reemplazado cada vez que se llama varias veces, sólo marque una de sus propiedades IBOutlet retenidas para NULL. si se NULL, a continuación, volver inmediatamente.

¿Alguien tiene alguna pista de por qué esto está sucediendo de esta manera?

efecto secundario de esto: no se puede utilizar de forma fiable awakeFromNib

.

No se puede asumir viewDidLoad se llamará sólo una vez. Si va a inicializar objetos y desea una garantía de hacer la inicialización ya sea en el método init o si va a cargar desde un archivo semilla del método awakeFromNib.

Yo tenía un problema similar y fue el resultado de cambiar el nombre de mi archivo XI ter y su clase ViewController (propietario del archivo). No hagas eso - como realmente consiguió los puntos de vista y delegados mal definido dentro del XML y no era recuperable. Mientras tanto, tenía una referencia a la carga de la VC original que se supone que es mi nuevo VC. Creo que hizo que el padre de recrear en sí y luego la CV que fue realmente trató de invocar. Básicamente, he creado una repetición indirecta a la VC que tiene entradas viewDidLoad x2 en mi rastro.

No creo que haya ninguna razón válida para viewDidLoad x2 ya que es una génesis y puede invocar otra inicialización con el mal asume precondiciones. Cada vez que he visto el viewDidLoad x2, que era un error de codificación de mi parte - muy a menudo cuando estaba refactorización y moviéndose alrededor de las clases VC

.

Si hay una razón válida para más de viewDidLoad de guardia, por favor alguien (Apple Dev estas escuchando) lo explican en detalle técnico -. He estado buscando esa respuesta durante meses

he tenido este problema, pero era capaz de solucionarlo.

Solución

Renombrar la clase controlador de vista que se carga dos veces.

Detalles

Cambiar el nombre y hacer que el nuevo nombre de algo totalmente nuevo. Cambiar el nombre del archivo no se detiene la emisión de carga dos veces. Creación de un nuevo proyecto (como se sugiere por otros) podría ser excesiva, por lo menos tratar las soluciones más simples primero! Cambiar el nombre de la clase del destino VC.

Sugerencia: : Si el cambio de nombre de la clase solucione el problema, entonces, evidentemente, tiene que actualizar todas sus referencias a esa clase. Puede acelerar este proceso mediante el uso de Comando + Mayúsculas + F para encontrar en todo el proyecto.

Me encontré con el mismo problema que yo estaba rediseñando un ViewController desde cero para deshacerse del archivo XI ter y para hacer que la clase reutilizable. Tenía esta segunda instancia ViewController que recibiría un mensaje viewDidLoad seguido de un mensaje dealloc.

Me enteré de esto fue el resultado del método loadView no ser redefinido en el ViewController. El loadView defecto llamada awakeFromNib, con la propiedad nibName establece en el nombre de la clase. A pesar de que me había quitado el archivo XI ter del proyecto, que todavía estaba en el directorio de la aplicación en el simulador.

Así que, aunque sólo podría restablecer el contenido y la configuración del simulador para deshacerse de la segunda viewDidLoad, una mejor manera puede ser simplemente redefinir loadView como esto:

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

Tiene sentido si se tiene en cuenta la documentación de la propiedad vista UIViewController's:

  

Si accede a esta propiedad y su   Actualmente es el valor nulo, la vista   controlador llama automáticamente al   método loadView y devuelve el   resultante vista. El loadView por defecto   método intenta cargar la vista desde   el archivo semilla asociado a la vista   controlador (si existe). Si su vista   controlador no tiene una asociada   archivo de semilla, se debe anular el   loadView método y utilizarlo para crear   la vista raíz y todos sus subvistas.

En mi caso, no me di cuenta de que en realidad he asignado el RootViewController dos veces en:

application:didFinishLaunchingWithOptions: y applicationDidBecomeActive:

Sólo para añadir a esto, si está utilizando una función del sistema, tales como TouchID, a continuación, applicationWillResignActive en su AppDelegate obtendrá invocado y si va a decir, restablecer controladores a un controlador Root Secure entonces obtendrá reinvoked, y performSegueWithIdentifier (self.MAIN_SEGUE, remitente: uno mismo)! no va a disparar

Esto me sucedió cuando me fundí un proyecto del guión a la vieja manera usando xibs para la construcción de puntos de vista. La principal razón para cambiar de nuevo fue el hecho de que no podía poner correctamente una vista modal correctamente. La forma en que suele hacer es por tener un método delegado de un UIButton construir una instancia de un determinado ViewController, establecer algunas de sus propiedades (siendo el más uno importación el delegado para que pueda desechar adecuadamente el controlador de vista modal de nuevo) y a continuación presente de una forma modal. En la nueva forma del guión gráfico, esto se supone que hace con un segue. Personalización de la transición sólo es factible mediante una clase personalizada que extiende la clase UIStoryboardSegue. Me parece demasiada molestia en comparación con la forma más sencilla que solía ser, así que fusiona de nuevo.

¿Cómo esta causa que yo tenga una carga viewcontroller dos veces? Al transferir el código del proyecto del guión gráfico al proyecto xib, hice un par de xibs (uno para cada ViewController) y copiado el objeto viewcontroller de un guión. Esto llevó a una xib con en él no es un Viw, sino una viewcontroller; lo que significa que había puesto una viewcontroller en un viewcontroller (ya que el propietario del archivo es también una instancia de la viewcontroller). No creo que en su caso que usted ha tenido este problema, pero espero que tal vez ayude a alguien algún día.

Para solucionar este mover la vista desde el controlador de vista de la controlador de vista y para el nivel de la raíz de la sección de objetos. Tanto el controlador de la vista y del elemento de navegación deberían suprimirse. Generar y ejecutar y debería ver sólo una asignación para el controlador de vista. Este es el propietario del archivo.

¿Qué pasa si su código no acceder a la propiedad vista cuando no se carga, sin embargo, el controlador de vista creará simplemente vista vacía y que podría desencadenar view did load accidentalmente.

El error más usual está accediendo vistas Bien durante la inicialización. Puede haber algo de acceso de propiedad (setter) que se invoca por xib debe acceder a la vista de propiedad accidentalmente.

¿Qué pasa si una propiedad está anotado con IBInspectable usted debe tener para comprobar isViewLoaded antes de aplicar un poco de valor a la vista.


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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top