¿Estoy abusando de la Subclass UIViewController?

Al tratar de entender por qué no se llamaba viewWillAppear en mi aplicación, me encontré con lo que puede ser un gran malentendido sobre el uso pretendido de las subclasss UIViewController.

De acuerdo con la siguiente publicación, viewWillAppear no se ejecuta al usar addSubView! y el enlace a esta publicación de blog: http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/ La subclass UIViewController solo debería ocurrir en situaciones muy específicas. Más notablemente, cuando se agrega directamente a UIWindow u otro Apple creó controlleres personalizados como UINavigationControllers.

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

De hecho, pensé que esto era más o less la idea general de la implementación de Apple de MVC en general … Un VC en general, con otros VC debajo, todos felizmente recibidos los llamados methods de delegado.

Si hay muchas vistas (que, por definición, necesitan controlar) que van y vienen en una aplicación, y muchas pantallas, en el model descrito en esa publicación, cada pantalla debe tener una subclass maestra de VC, con todas las subvistas controladas en su lugar por controlleres personalizados (que suceden para controlar vistas) que son subclasss de NSObject simple.

En este caso, UIViewControllers solo debe estar directamente en Window o UINavigationController, UITabBarController etc?

¿Estás seguro de que en ese caso se llamarán los methods de delegado de UIVC? ¿Cómo difiere esto de llamar manualmente a los methods delegates cuando la vista del controller de vista es una subvista de otro VC?

Sinceramente, esto parece una tremenda pérdida de time. Implementaciones personalizadas de ViewDidLoad, viewDidLoad, viewDidUnload, viewWillAppear, viewWillDisappear sin mencionar cosas tan simples como properties como, por ejemplo, "view" …

Básicamente, o bien he estado completamente equivocado, o estoy en una persecución salvaje. Si las subclasss UIViewController no pueden contarse para llamar a viewWillAppear, ¿por qué no llamar a ese método manualmente y terminar con él?

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

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

Básicamente, o bien he estado completamente equivocado, o estoy en una persecución salvaje.

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

  • Una vista es, por supuesto, cualquier object que sea una instancia de UIView o una subclass de UIView.
  • En el context de MVC, "view" se usa colectivamente, y hablamos de que esto o lo otro son "la responsabilidad de la vista", aunque "la vista" es realmente un grupo de objects.
  • Cuando se habla de un controller de vista, la "vista" que administra el controller es la instancia de UIView a la que la vista del controller apunta y la jerarquía de subvenciones que contiene.

Parece que su malentendido está en este último punto. Un controller de vista debe administrar un solo "pantalla" de contenido. Si está utilizando un object de controller de vista única para administrar más de una jerarquía de vista, o si está utilizando varios controlleres de vista para administrar diferentes partes de la misma jerarquía de vista, está utilizando UIViewController de una manera que nunca fue pensada y que es probable que lleve a problemas.

Los methods que ha mencionado (-viewDidLoad, -viewWillAppear, etc.) están destinados a decirle al controller de vista que su jerarquía de vista se acaba de cargar, que está a punto de mostrarse, y así sucesivamente. Realmente no tienen la intención de referirse a una subvista individual, y sería inusual que un controller de vista necesite esa información para subvenciones individuales. Si se cargó la jerarquía de vista, el controller de vista sabe que todo lo que estaba en esa jerarquía se cargó.

Pareces estar interpretando estos methods como methods de delegado, pero no lo son. Un delegado es un object separado que permite la personalización del delegador sin necesidad de subclasss. -viewDidLoad y -viewWillAppear son dos ejemplos de puntos de anulación para UIViewController, una class que está destinada a subclasss. El object controller de vista llama a estos methods por sí mismo para dar a las subclasss la oportunidad de tomar alguna acción en un punto interesante en el ciclo de vida del controller.

Si las subclasss UIViewController no pueden contarse para llamar a viewWillAppear, ¿por qué no llamar a ese método manualmente y terminar con él?

Observe bien UIViewController y verá que la mayor parte de la funcionalidad proporcionada tiene que ver con mostrar la vista (es decir, la jerarquía de vistas) en la pantalla o con la integración del controller con controlleres de vista "contenedor" como UINavigationController y UITabBarController. Nada de eso es útil para los objects que no gestionan toda la pantalla de contenido.

A veces sucede que un grupo de vistas se replicará en varias pantallas, y en algunos de esos casos, es útil administrar esas vistas con un object que está separado del controller de vista en sí. Puedo ver cómo te sentirías tentado de usar UIViewController debido a su -viewDidLoad y methods similares, pero esos son realmente solo una pequeña parte de lo que hace UIViewController. ¿Qué significaría llamar -presentModalViewController: en uno de esos objects? ¿O para acceder a sus properties navigationController o parentViewController ?

Si realmente desea administrar subvistas de la jerarquía de vista de su controller de vista con esos methods, cree una subclass de NSObject que tenga los methods -ViewDid [Load | Unload | Appear | Disappear] y -viewWill [Appear | Disappear]. Puede crear esa class una vez y luego subclamarla tan a menudo como necesite, y ninguna de sus classs de "subcontroller" tendrá todas las cosas extra, innecesarias de administración de controlleres que viene junto con UIViewController.

Editar: Quiero agregar un puntero aquí a la Guía de Progtwigción de Controles de Apple para iOS , que proporciona mucho soporte para lo que he descrito anteriormente. Aquí hay un pasaje relevante de la subsección titulada "Ver controlleres controlar una jerarquía de vistas":

Los controlleres de vista se asocian directamente con un object de vista única, pero ese object es a menudo la vista raíz de una jerarquía de vista mucho más grande que el controller de vista también administra. El controller de vista actúa como el agente de coordinación central para la jerarquía de vistas, manejando intercambios entre sus vistas y cualquier controller o objects de datos relevantes. Un controller de vista única normalmente gestiona las vistas asociadas con el contenido de una sola pantalla, aunque en las aplicaciones de iPad esto puede no ser siempre el caso.

Ver la Guía de progtwigción del controller es necesaria para cualquier persona, incluso pensando en escribir una aplicación para iOS. Vale la pena revisar si no lo ha leído por un time (o nunca).

Actualización: A partir de iOS 5, ahora es posible definir sus propios controlleres de vista de contenedor, es decir, ver controlleres que administran otros controlleres de vista y mostrar potencialmente las vistas de varios controlleres de vista al mismo time. Puede leer más sobre esto en la guía vinculada anteriormente en la sección titulada Creación de controlleres personalizados de vista de contenedor . Nada de esto realmente cambia los puntos esenciales anteriores: un controller de vista única aún debe administrar una jerarquía de vistas, y los methods como -viewDidLoad todavía se refieren a todo el gráfico de vista en lugar de a subviews individuales. El consejo de que un controller de vista gestiona un contenido "completo con pantalla" ya no es completamente preciso; al igual que UISplitViewController ha mostrado contenido desde dos controlleres de vista simultáneamente desde la introducción del iPad, sus propios contenedores ahora pueden mostrar las vistas de múltiples controlleres de vista infantil. Escribir un controller de vista de contenedor es un tema un tanto avanzado: debería estar muy familiarizado con el uso de los controlleres de vista en general y la forma en que funcionan los controlleres de vista de contenedor provistos antes de tomar una puñalada para crear el suyo propio.