Estoy buscando crear un objeto de entorno al que pueda acceder el modelo de vista (no solo la vista).
El objeto Environment rastrea los datos de la sesión de la aplicación, por ejemplo, loginIn, token de acceso, etc., estos datos se pasarán a los modelos de vista (o clases de servicio cuando sea necesario) para permitir que una API pase datos de estos ObjectObjects.
He intentado pasar el objeto de sesión al iniciador de la clase de modelo de vista desde la vista, pero aparece un error.
¿Cómo puedo acceder / pasar el EnvironmentObject al modelo de vista usando SwiftUI?
Ver enlace al proyecto de prueba: https://gofile.io/?c=vgHLVx
Respuestas:
Elijo no tener un ViewModel. (¿Quizás es hora de un nuevo patrón?)
He configurado mi proyecto con ay
RootView
algunas vistas secundarias. Configuré miRootView
con unApp
objeto como EnvironmentObject. En lugar de que ViewModel acceda a Modelos, todas mis vistas acceden a clases en la aplicación. En lugar de que ViewModel determine el diseño, la jerarquía de vistas determina el diseño. Al hacer esto en la práctica para algunas aplicaciones, he descubierto que mis puntos de vista siguen siendo pequeños y específicos. Como una simplificación excesiva:En mis avances, inicializo un
MockApp
que es una subclase deApp
. MockApp inicializa los inicializadores designados con el objeto Mocked. Aquí el UserService no necesita ser burlado, pero la fuente de datos (es decir, NetworkManagerProtocol) sí.fuente
app.userService.logout()
.userService
debe ser privado y acceder solo desde dentro de la clase de aplicación. El código anterior debería verse así:Button(action: { app.logout() })
y la función de cierre de sesión llamará directamenteuserService.logout()
.No deberías Es un error común pensar que SwiftUI funciona mejor con MVVM.
MVVM no tiene lugar en SwfitUI. Estás preguntando si puedes empujar un rectángulo para
encajar en forma de triángulo. No encajaría.
Comencemos con algunos hechos y trabajemos paso a paso:
ViewModel es un modelo en MVVM.
MVVM no tiene en cuenta el tipo de valor (p. Ej., No existe tal cosa en Java).
Un modelo de tipo de valor (modelo sin estado) se considera más seguro que la referencia
modelo de tipo (modelo con estado) en el sentido de inmutabilidad.
Ahora, MVVM requiere que configure un modelo de tal manera que siempre que cambie,
Actualiza la vista de alguna manera predeterminada. Esto se conoce como vinculante.
Sin vinculación, no tendrá una buena separación de preocupaciones, por ejemplo; refactorizando
modelo y estados asociados y mantenerlos separados de la vista.
Estas son las dos cosas que la mayoría de los desarrolladores MVVM de iOS fallan:
iOS no tiene un mecanismo "vinculante" en el sentido tradicional de Java.
Algunos simplemente ignorarían el enlace y pensarían en llamar a un objeto ViewModel
resuelve todo de forma automática; algunos introducirían Rx basado en KVO, y
complica todo cuando se supone que MVVM simplifica las cosas.
modelo con estado es demasiado peligroso
porque MVVM puso demasiado énfasis en ViewModel, muy poco en la gestión del estado
y disciplinas generales en la gestión del control; la mayoría de los desarrolladores terminan
pensar que un modelo con estado que se usa para actualizar la vista es reutilizable y
comprobable .
esta es la razón por la cual Swift introduce el tipo de valor en primer lugar; un modelo sin
estado.
Ahora a su pregunta: ¿pregunta si su ViewModel puede tener acceso a EnvironmentObject (EO)?
No deberías Porque en SwiftUI un modelo que se ajusta a Ver automáticamente tiene
referencia a EO. P.ej;
Espero que la gente pueda apreciar cómo está diseñado el SDK compacto.
En SwiftUI, MVVM es automático . No hay necesidad de un objeto ViewModel separado
que se une manualmente a la vista que requiere que se le pase una referencia EO.
El código anterior es MVVM. P.ej; Un modelo con unión para ver.
Pero debido a que el modelo es un tipo de valor, en lugar de refactorizar el modelo y el estado como
Ver modelo, refactoriza el control (en la extensión de protocolo, por ejemplo).
Este es el SDK oficial que adapta el patrón de diseño a la función de idioma, en lugar de solo
haciendo cumplir Sustancia sobre la forma.
Mira tu solución, tienes que usar singleton que es básicamente global. usted
debe saber lo peligroso que es acceder a cualquier lugar global sin protección de
inmutabilidad, que no tiene porque tiene que usar el modelo de tipo de referencia.
TL; DR
No haces MVVM de manera Java en SwiftUI. Y la forma rápida de hacerlo no es necesario
para hacerlo, ya está incorporado.
Espero que más desarrolladores vean esto, ya que esto parecía una pregunta popular.
fuente
A continuación se proporciona un enfoque que funciona para mí. Probado con muchas soluciones comenzadas con Xcode 11.1.
El problema se originó por la forma en que EnvironmentObject se inyecta a la vista, esquema general
es decir, en la primera vista creada, en el segundo objeto del entorno creado, en el tercer objeto del entorno inyectado en la vista
Por lo tanto, si necesito crear / configurar el modelo de vista en el constructor de vistas, el objeto de entorno todavía no está presente.
Solución: separe todo y use inyección de dependencia explícita
Así es como se ve en el código (esquema genérico)
No hay ninguna compensación aquí, porque ViewModel y EnvironmentObject son, por diseño, tipos de referencia (en realidad
ObservableObject
), por lo que paso aquí y allá solo referencias (también conocidos como punteros).fuente