¿Estoy abusando de UIViewController Subclassing?

Al tratar de descubrir por qué no se llamaba a ViewWillAppear en mi aplicación, me di cuenta de lo que podría ser un gran malentendido sobre el uso previsto de las subclases UIViewController.

De acuerdo con la siguiente vista posterior, ¡ WillAppear no se ejecuta cuando se utiliza addSubView! y el enlace a esta entrada del blog: http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/ Las subclases de UIViewController solo deberían ocurrir en situaciones muy específicas. Más notablemente cuando se agrega directamente a UIWindow, u otros controladores personalizados creados por Apple como UINavigationControllers.

Ciertamente soy culpable de agregar las vistas de las subclases UIViewController a las vistas de otras subclases UIViewController.

De hecho, pensé que esto era más o menos la idea general de la implementación de MVC por parte de Apple … Un VC general, con otros VCs por debajo, todos felizmente recibiendo sus métodos de delegado.

Si hay muchas vistas (que por definición necesitan control) que entran y salen en una aplicación, y muchos screenfulls, en el modelo descrito en esa publicación, cada screenfull debe tener una Subclase maestra VC, con todas las subvistas controladas en lugar de controladores personalizados (que pasan a controlar las vistas) que son subclases de NSObject simple.

En este caso, UIViewControllers solo debe estar directamente en la ventana o UINavigationController, UITabBarController, etc.

¿Está garantizado que recibirá los métodos del delegado UIVC llamados en ese caso? ¿Cómo difiere esto de llamar manualmente a los métodos de delegado cuando la vista de un viewcontroller es una subvista de otro VC?

Honestamente, esto parece una gran pérdida de tiempo. Implementaciones personalizadas de ViewDidLoad, viewDidLoad, viewDidUnload, viewWillAppear, viewWillDisappear para no mencionar cosas tan simples como propiedades como, por ejemplo, “ver” …

Entonces, básicamente, o he estado completamente equivocado, o estoy en una loca búsqueda. Si no se puede contar con las subclases de UIViewController para llamar a viewWillAppear, ¿por qué no simplemente llamar a ese método manualmente y terminarlo?

¿Por qué replicar toda la funcionalidad percibida de UIViewController?

Respuesta a la pregunta del título: Sí.

Entonces, básicamente, o he estado completamente equivocado, o estoy en una loca búsqueda.

Parece que has estado completamente equivocado. El término “vista” tiene algunos significados diferentes pero relacionados:

  • Una vista es, por supuesto, cualquier objeto que sea una instancia de UIView o una subclase de UIView.
  • En el contexto de MVC, “ver” se usa colectivamente, y hablamos de que tal o cual es “la responsabilidad de la vista”, aunque “la vista” es realmente un grupo de objetos.
  • Cuando se habla de un controlador de vista, la “vista” que administra el controlador es la instancia de UIView a la que apunta la vista del controlador y la jerarquía de las subvistas que contiene.

Parece que tu malentendido está en este último punto. Un controlador de vista debe administrar una única “pantalla” de contenido. Si está utilizando un objeto de controlador de vista única para administrar más de una jerarquía de vistas, o si está usando varios controladores de vista para administrar diferentes partes de la misma jerarquía de vistas, está usando UIViewController de una manera que nunca fue intencional y que es probable que conduzca a problemas.

Los métodos que mencionó (-viewDidLoad, -viewWillAppear, etc.) están destinados a decirle al controlador de vista que su jerarquía de vista acaba de cargarse, está a punto de mostrarse, y así sucesivamente. En realidad, no están destinados a referirse a una subvista individual, y sería inusual que un controlador de vista necesitara recibir esa información para las subvistas individuales. Si se cargó la jerarquía de vista, el controlador de vista sabe que todo lo que estaba en esa jerarquía se cargó.

Parece que está interpretando estos métodos como métodos delegates, pero no lo son. Un delegado es un objeto separado que permite la personalización del delegador sin la necesidad de subclases. -viewDidLoad y -viewWillAppear son dos ejemplos de reemplazos de puntos para UIViewController, una clase que está destinada para la creación de subclases. El objeto controlador de vista llama a estos métodos para dar a las subclases la oportunidad de realizar alguna acción en un punto interesante del ciclo de vida del controlador.

Si no se puede contar con las subclases de UIViewController para llamar a viewWillAppear, ¿por qué no simplemente llamar a ese método manualmente y terminarlo?

Eche un vistazo a UIViewController y verá que la mayor parte de la funcionalidad proporcionada tiene que ver con mostrar la vista (es decir, la jerarquía de vista) en la pantalla, o con la integración del controlador con controladores de vista de “contenedor” como UINavigationController y UITabBarController. Nada de eso es útil para objetos que no están administrando toda la pantalla de contenido.

Ocurre a veces que un grupo de vistas se replicará en varias pantallas, y en algunos de esos casos es útil administrar esas vistas con un objeto que está separado del controlador de vista. Puedo ver cómo te sentirías tentado de usar UIViewController debido a its -viewDidLoad y métodos similares, pero esos son realmente solo una pequeña parte de lo que hace UIViewController. ¿Qué significa llamar a -presentModalViewController: en uno de esos objetos? ¿O para acceder a sus propiedades navigationController o parentViewController ?

Si realmente desea administrar las subvistas de la jerarquía de vistas de su controlador de vista usando esos métodos, cree una subclase de NSObject que tenga métodos -viewDid [Cargar | Descargar | Aparecer | Desaparecer] y -visualizará [Aparecerá | Desaparecerá]. Puede crear esa clase una sola vez y luego subclasificarla tantas veces como lo necesite, y ninguna de sus clases de “subcontrolador” tendrá todas las cosas de gestión de controladores adicionales e innecesarias que se incluyen con UIViewController.

Editar: Quiero agregar un puntero aquí a la Guía de progtwigción del controlador de vista de Apple para iOS , que brinda mucho apoyo para lo que he expuesto anteriormente. Aquí hay un pasaje relevante de la subsección titulada “Controladores de vista Gestionar una jerarquía de vista”:

Los controladores de vista están asociados directamente con un único objeto de vista, pero ese objeto a menudo es solo la vista raíz de una jerarquía de vista mucho más grande que también es administrada por el controlador de vista. El controlador de vista actúa como el agente coordinador central para la jerarquía de vistas, manejando los intercambios entre sus vistas y cualquier controlador relevante u objetos de datos. Un controlador de vista única generalmente administra las vistas asociadas con el contenido de una sola pantalla, aunque en las aplicaciones de iPad esto no siempre es el caso.

Ver la Guía de progtwigción del controlador es una lectura obligatoria para cualquier persona que esté pensando en escribir una aplicación de iOS. Vale la pena revisar si no lo ha leído en mucho tiempo (o nunca).

Actualización: comenzando con iOS 5, ahora es posible definir sus propios controladores de vista de contenedor, es decir, ver controladores que administran otros controladores de vista y potencialmente mostrar las vistas de múltiples controladores de vista al mismo tiempo. Puede leer más sobre esto en la guía vinculada anteriormente en la sección titulada Cómo crear controles de vista de contenedor personalizados . Nada de esto realmente cambia los puntos esenciales anteriores: un controlador de vista única aún debe administrar una jerarquía de vistas, y métodos como -viewDidLoad todavía se refieren a todo el gráfico de vista en lugar de a subvistas individuales. El consejo de que un controlador de vista administra una “pantalla completa” de contenido ya no es completamente preciso, así como UISplitViewController ha mostrado contenido de dos controladores de vista simultáneamente desde la introducción del iPad, sus propios contenedores ahora pueden mostrar las vistas de múltiples Controladores de vista infantil. Escribir un controlador de vista de contenedor es un tema algo avanzado: usted debe estar muy familiarizado con el uso de los controladores de vista en general y la forma en que funcionan los controladores de vista de contenedor antes de intentar crear el suyo propio.