¿Mejor enfoque para componer UIViews para crear vistas complejas?

Al pasar de la stack web a las maravillas de iOS , me resulta difícil entender cómo reestructurar mis pensamientos para MVC y estructurar de manera efectiva mi interfaz de usuario en iOS.

Premisa:

  • En la stack web:
    • El controller generalmente corresponde a una URL y la vista representa la página.
    • Las vistas tienen forms de no repetir el código con fragments CSS + Javascript +.
  • En iOS:
    • Una vez en una nueva pantalla que corresponda a UIViewController.
    • Tenemos una UIView que compone sus propias UIViews.
    • UIViews existe con UIViews, UIViewController con UIViews, UIViewController con UIViews en línea
    • Definimos definitivamente la lógica de carga o de datos pesados ​​al controller más cercano
    • Se siente principalmente Ver primero en iOS que es genial

Pregunta:

¿Cuál es la mejor forma de pensar acerca de cómo componer vistas para mí? self.view :

  • Una vista como class UIView
  • Una vista que se produce como UIViewController con una class UIView asociada.
  • Una vista que se produce como UIViewController con UIViewController en línea

Ejemplo de jerarquía de vista:

 ------------------------------ | A | | | | -------------------- | | | B | | | | | | | | -------------- | | | | | C | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | -------------- | | | | | | | -------------------- | | | ------------------------------ 

[Detalles para ser específicos] Mis experiencias ~ ~ incómodas:

  • A podría [self addView:B_view] (Si B era solo UIView)
  • A también podría [self addView:B_viewController.view] (Si B tuviera un controller de vista)
  • A también podría [B setChildView:C_view]
  • Podemos tener B_viewController.delegate = A & C_viewController.delegate = A
  • Podemos tener B_viewController.delegate = A & C_view.delegate = B
  • Después de todos estos casos coexistentes, tenemos que pensar en los límites
  • Veo las preocupaciones de C respondidas por A a través de largas cadenas de delegates.

La lógica está repartida entre delegates, viewControllers y vistas .

Separar las preocupaciones, pero ¿cómo?

Aparte del argumento "bien abstracto y separación de preocupaciones" que puede mejorar las experiencias anteriores. Creo que es el sangrado de viewController y viewController.view está compuesto para causar fácilmente un acoplamiento extenso.

Esto rápidamente se vuelve confuso y se siente como un espagueti y difícil de controlar a pesar de los esfuerzos.

Dicho esto,

  • ¿Cuáles son las mejores prácticas para abordar las trampas anteriores?
  • ¿Qué es lo que no se debe hacer?
  • ¿Cómo evitamos largas cadenas de delegates cuando es difícil plantear buenos arguments, ya que al delegar su eficacia, dice que puede manejar esto mejor?

Fallé al hacer preguntas igualmente amplias en stackoverflow – parece que la comunidad favorece una pregunta técnica más específica. Pero lo intentaré. Tenga en count que todos los siguientes son mis opiniones y no las reglas difíciles y rápidas.

Siento que es una pregunta compuesta sobre el paso de posts y los patrones de layout. En términos de comunicación de componentes (ya sean vistas o controller) hay muchas maneras de hacerlo, cada uno tiene sus + y - (o más bien, casos de uso). Hay: delegación, cadena de respuesta, bloques, notifications, señal reactiva, solo para nombrar unos pocos.

TL; DR

  • Mi preference personal es mantener la vista lo más simple posible y poner la lógica comercial en otro lugar (dependiendo del patrón que elija), lo que permitirá una mejor composition.
  • Tu instinto se alinea con el mío: cada vez que tu componente (ver o ver el controller) está haciendo self.superview o self.parentViewController (algunos dicen incluso self.navigationController ) probablemente viole la encapsulación y hay una mejor manera.
  • Las largas cadenas de delegates son definitivamente un problema. A veces son fáciles de seguir, otras no, pero no es lo peor del mundo, aunque es probable que haya una mejor manera de manejar la comunicación.

Las siguientes son algunas observaciones aleatorias que pueden llevarte a algún lado (o no).

MVC es una forma rápida (y sucia) de hacer que la gente en iOS

En mi opinión, MVC es un gran patrón para proyectos pequeños (es fácil desde "fácil vs simple"). Pero a partir de la experiencia personal, rápidamente se descontrola cuando la complejidad de la pantalla en la que está trabajando crece. La tendencia es que el controller maneje todo, desde la interacción del usuario al trabajo en networking, y se convierte en un monstruo de 1 k de largo realmente rápido.

Tristemente, mucha architecture de iOS confía en UIViewController . A menudo, se convierte inevitablemente en un primer punto de contacto de su código con el sistema operativo, pero no tiene que manejar todo internamente. En cambio, puede encaminar las responsabilidades hacia los componentes apropiados, es decir

 func loginButtonDidTap(_ sender: UIButton) { loginManager.beginLogin(from: self) analytics.reportLogin(with: sender) // ... } 

Está bien componer controlleres también

No me di count de su descripción, pero si prefiere ir con MVC es una opción completamente válida para componer controlleres. Es una situación muy común cuando se construye para iPad, pero incluso en iPhone, cada pantalla puede include fácilmente piezas completamente independientes en las que cada una de ellas es un ViewController separado, entonces deberías search en lo que se llama "contención UIViewController". Sobre todo permite una mejor separación y reutilización, pero una vez más, no resuelve el problema principal.

Definitivamente explorar otros patrones

Si estás leyendo esto, estás muy ansioso por aprender. En este caso, te sugiero que no pares en MVC. Hay muchos patrones de layout interesantes que podrían o no ser adecuados para sus necesidades particulares. MVVM era (es?) Bastante popular. Últimamente, el flujo unidireccional parece ser lo nuevo. Inspirado por JS's Redux. Es una gran desviación de MVC y sugiero revisar este proyecto en https://github.com/ReSwift/ReSwift si está interesado.

Lamentablemente, como cualquier pregunta arquitectónica, no hay nada bueno o malo: solo hay cosas que funcionan para usted y su equipo o no. Y me encantaría escuchar otras perspectivas antes de que la pregunta se cierre como "demasiado amplia" 🙂

Lo siento si esto no es completamente lo que pediste, avísame si hay algún aspecto particular que te gustaría discutir.

Tal vez, lo que está tratando es con el dilema MVC – Controladores de visión masiva. Aquí hay una lectura interesante donde Marcus habla sobre el event handlingl código de manera efectiva al poner el código donde pertenece, la capa de networking, la capa de persistencia o la capa de presentación (idealmente el controller de vista).

http://www.cimgf.com/2015/09/21/massive-view-controllers/

Además del patrón de delegación, también tenemos un enfoque basado en bloque / cierre que podría ayudar a limpiar el código.

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html

En general, el enfoque de código limpio de Robert C. Martin podría ser de ayuda aquí. La forma de implementarlo a través de algo llamado como architecture VIPER. Aquí hay un tutorial sobre eso.

https://www.objc.io/issues/13-architecture/viper/

Objetivo C, ya que un lenguaje abarca el patrón de delegación y es una práctica estándar usarlo para la mayoría de las preocupaciones.

Bienvenido a la plataforma iOS.

  • Puede tener un ViewController

  • Tener UIViews separadas para ViewController. No debe estar estrechamente acoplado con viewController.

  • Haga que su vista de inicio de session en la class UIView en sí. Cree su propio delegado y protocolos. y utilícelo en cualquier control de vista.

  • Agregar viewcontroller a viewcontroller no es una buena solución.

  • También puede pasar a MVVM donde cada vista tendrá su parte lógica en su Modelo de vista, pero puede ser confuso al principio.

  • Intente hacer UIViews separados para ViewControllers.

Como alguien que ha hecho una buena cantidad de progtwigción de iOS, y ahora está pasando mucho time en el desarrollo angular, aquí hay algunas ideas rápidas:

Una UIView representa el bloque fundamental de la pantalla; es decir, compromete una vista, algunos datos y la lógica para representar esos datos en la vista. Por lo tanto, se puede usar para dibujar text o charts, o puede contener cualquier cantidad de subvistas que tengan la misma capacidad. En el mundo Angular, una UIView sería (algo) equivalente a un Component que encapsula HTML , CSS , JavaScript , etc., pero también podría include otros componentes.

Como sabes, iOS proporciona muchas UIView's UILabel , UIButton , UITable , UITable , etc., UITable , y son adecuadas para la mayoría de las necesidades de la aplicación.

Un UIViewController tiene una function más estructural que una UIView . Se integra con el marco de navigation para que el desarrollador pueda cambiar rápidamente el context para el usuario. Contiene una UIView "principal" que sirve como plataforma base para el context, que contiene cualquier número de UIView's nativos y personalizados. Su propósito es ayudar a configurar esas UIViews dado el context actual de la aplicación .

Si un UIViewController está configurando una UIView de maneras que no están limitadas al context de la aplicación actual, entonces la UIView probablemente debería extenderse a un object personalizado. De esta forma, puede autogestionar y es más fácil reutilizar en otros contexts.

Otra cosa:

Los delegates son geniales cuando es apropiado, pero NSNotification es una forma simple y poderosa de observar los cambios mientras se evitan los espaguetis de las dependencies de objects.