iOS: dónde inicializar vistas

Si quiero inicializar vistas de forma programática, ¿en qué parte del ciclo de vida de viewcontroller debería ocurrir esto?

La intuición inicial es loadView . Sin embargo, aquí, aún no tenemos el marco de la vista en sí (necesario para calcular los tamaños / posiciones de las vistas). Lo mismo para viewDidLoad .

La siguiente intuición es viewWillAppear – aquí HACEMOS (finalmente) tener una garantía del marco de la vista. Sin embargo, esto tiene potencial para ser llamado muchas veces a lo largo del ciclo de vida de VC. Lo mismo para viewDidAppear , etc …

Finalmente, encontré viewWillLayoutSubviews . Esto funciona para la initialization de la mayoría de los layouts estáticos; sin embargo, cada vez que cualquier vista se mueve, se vuelve a llamar (el mismo problema que viewWillAppear ).

He visto recomendaciones para iniciar las vistas en loadView y establecer sus frameworks en viewWillLayoutSubviews (ya que los frameworks de configuration deben ser idempotent, a quién le importa si se llama un par de veces). Pero entonces, ¿por qué Apple alienta tanto a initWithFrame: como el método de initialization estándar de UIViews ( https://developer.apple.com/library/ios/documentation/windowsviews/conceptual/viewpg_iphoneos/CreatingViews/CreatingViews.html )?

¿Sería una locura subclassar todos mis UIViewControllers para tener un método initWithViewFrame 😕 De esa forma puedo pasar en un marco, configurar manualmente de inmediato en loadView y terminar con él? ¿O es mejor tener un viewHasBeenFormatted flag en viewWillAppear que, si no está configurado, llama al formatting de vistas y luego lo establece?

¿O es solo la forma en que Apple dice "usar el creador de interfaces o estás jodido"?

¡Se agradece cualquier ayuda!

editar : escribí accidentalmente loadView donde quería decir viewWillAppear (en el párrafo final)

actualización : supongo que he llegado a un acuerdo con el hecho de que no hay lugar donde

  1. El marco se conoce con confianza.
  2. El código solo se ejecutará una vez (en la configuration)

Parece que se espera que initWithFrame: todas sus vistas en viewDidLoad (pero luego creo que el contenido de esa vista no debe tratar ese marco incluso remotamente final, porque ¿cómo podría ser cuando se derivó de una suposition? Ugh. …) Luego vuelva a configurar sus frameworks en layoutSubviews . Y asegúrese de manejar manualmente las diferencias entre el layout inicial y el layout como resultado de una vista movida allí … Hombre siento que tengo que faltar algo … (lol denegación …)

Supongo que, O envíe y use IB.

update2 : viewWillLayoutSubviews se llamará cuando se cambie el tamaño de una de sus subvistas. Por lo tanto, sigue siendo descalificado ya que falla la propiedad 2 de las características requeridas que estoy buscando. Significado de la palabra

Si está haciendo un layout con IB, está bien hacer una initialization de vista adicional en viewDidLoad (por ejemplo, si necesita hacer cosas que IB no maneja bien, o si tiene subclasss UIView con properties no admitidas por IB). Alternativamente, si no está utilizando IB, la documentation dice que debe usar loadView para inicializar manualmente su jerarquía de vistas.

Tienes razón, sin embargo, de que no puedes confiar en que el marco sea preciso en ese momento. Por lo tanto, puede realizar el layout a través de la propiedad autoResizingMask cada vista, las restricciones de layout (si es iOS 6 y posteriores) y / o replace las layoutSubviews .

Mi enfoque habitual es hacer un layout en algún grado en IB, luego hacer cualquier otra cosa que necesite (layout no trivial, classs personalizadas, etc.) en viewDidLoad . Entonces, si tengo layout para descubrir que autoResizingMask no cubre (estoy soportando hasta iOS 5), viewWillAppear (o layoutSubviews si estoy subclassando UIView ) y hago algunos cálculos de píxeles. Tengo una categoría en UIView para ayudar con esto que tiene cosas como:

 -(void)centerSubviewHorizontally:(UIView *)view pixelsFromTop:(float)pixels; -(void)centerSubviewHorizontally:(UIView *)view pixelsBelow:(float)pixels siblingView:(UIView *)sibling; 

Los controlleres de vista no deberían tener initWithFrame: methods. Lo que hago en todo mi código (nunca uso IB) es permitir que loadView pnetworkingeterminado loadView lo suyo. Creo y configuro todas las subvenciones en viewDidLoad . En este punto, el marco del controller de vista tiene al less un valor sensato. Todas las subcounts se pueden crear con sus propios cuadros sensibles en function del tamaño inicial de la vista del controller de vista. Con los valores correctos de autoresizingMask esto puede ser todo lo que necesita.

Si necesita un layout de subview más específico, coloque el código de layout apropiado en el método viewWillLayoutSubviews . Esto se ocupará de cualquier cambio en el marco de vista del controller de vista que incluya rotation, barras de estado de llamada entrante, etc.

Si no usa el generador de interfaces, debe anular LoadView e inicializar las vistas allí. Si usa la reproducción automática, también puede agregar sus restricciones allí. Si no utiliza la reproducción automática, puede anular el método layoutSubviews de sus vistas para ajustar los frameworks.