Je cherche à créer un EnvironmentObject auquel le modèle de vue peut accéder (pas seulement la vue).
L'objet Environnement suit les données de la session d'application, par exemple, LogIn, jeton d'accès, etc., ces données seront transmises aux modèles de vue (ou aux classes de service si nécessaire) pour permettre à l'appel d'une API de transmettre les données de ces EnvironmentObjects.
J'ai essayé de passer l'objet de session à l'initialiseur de la classe de modèle de vue à partir de la vue, mais j'obtiens une erreur.
comment puis-je accéder à / passer l'EnvironnementObjet dans le modèle de vue à l'aide de SwiftUI?
Voir le lien pour tester le projet: https://gofile.io/?c=vgHLVx
Réponses:
Je choisis de ne pas avoir de ViewModel. (Peut-être le temps d'un nouveau modèle?)
J'ai configuré mon projet avec une
RootView
et quelques vues enfant. J'ai configuré monRootView
avec unApp
objet comme EnvironmentObject. Au lieu que le ViewModel accède aux modèles, toutes mes vues accèdent aux classes sur l'application. Au lieu que le ViewModel détermine la disposition, la hiérarchie des vues détermine la disposition. Après avoir fait cela dans la pratique pour quelques applications, j'ai trouvé que mes vues restent petites et spécifiques. Comme simplification excessive:Dans mes aperçus, j'initialise un
MockApp
qui est une sous-classe deApp
. Le MockApp initialise les initialiseurs désignés avec l'objet Mocked. Ici, le UserService n'a pas besoin d'être moqué, mais la source de données (c'est-à-dire NetworkManagerProtocol) le fait.la source
app.userService.logout()
.userService
doit être privé et accessible uniquement depuis l'intérieur de la classe d'application. Le code ci-dessus devrait ressembler à ceci:Button(action: { app.logout() })
et la fonction de déconnexion appellera alors directementuserService.logout()
.Tu ne devrais pas. C'est une idée fausse que SwiftUI fonctionne mieux avec MVVM.
MVVM n'a pas sa place dans SwfitUI. Vous demandez que si vous pouvez pousser un rectangle
s'adapter à une forme de triangle. Ça ne rentrerait pas.
Commençons par quelques faits et travaillons étape par étape:
ViewModel est un modèle dans MVVM.
MVVM ne prend pas en compte le type de valeur (par exemple, rien de tel en java).
Un modèle de type valeur (modèle sans état) est considéré comme plus sûr que la référence
modèle de type (modèle avec état) au sens d'immuabilité.
Maintenant, MVVM vous oblige à configurer un modèle de telle sorte que chaque fois qu'il change, il
met à jour la vue d'une manière prédéterminée. C'est ce qu'on appelle la liaison.
Sans engagement, vous n'aurez pas une bonne séparation des préoccupations, par exemple; refactoring out
modèle et les états associés et en les gardant à l'écart
Ce sont les deux choses que la plupart des développeurs MVVM iOS échouent:
iOS n'a pas de mécanisme de «liaison» au sens traditionnel de Java.
Certains ignoreraient simplement la liaison et penseraient à appeler un objet ViewModel
résout automatiquement tout; certains introduiraient le Rx basé sur KVO, et
complique tout lorsque MVVM est censé simplifier les choses.
modèle avec état est tout simplement trop dangereux
parce que MVVM met trop l'accent sur ViewModel, trop peu sur la gestion des états
et disciplines générales dans la gestion du contrôle; la plupart des développeurs finissent par
penser qu'un modèle avec un état utilisé pour mettre à jour la vue est réutilisable et
testable .
c'est pourquoi Swift introduit le type de valeur en premier lieu; un modèle sans
Etat.
Maintenant à votre question: vous demandez si votre ViewModel peut avoir accès à EnvironmentObject (EO)?
Tu ne devrais pas. Parce que dans SwiftUI, un modèle conforme à View a automatiquement
référence à l'OE. Par exemple;
J'espère que les gens pourront apprécier la conception du SDK compact.
Dans SwiftUI, MVVM est automatique . Il n'y a pas besoin d'un objet ViewModel séparé
qui se lie manuellement à la vue qui nécessite une référence EO qui lui est transmise.
Le code ci-dessus est MVVM. Par exemple; un modèle avec reliure à voir.
Mais parce que le modèle est un type de valeur, au lieu de refactoriser le modèle et l'état comme
voir le modèle, vous refactorisez le contrôle (dans l'extension de protocole, par exemple).
Il s'agit du modèle de conception du SDK qui s'adapte aux fonctionnalités linguistiques, plutôt que simplement
le faire respecter. La substance plus que la forme.
Regardez votre solution, vous devez utiliser singleton qui est fondamentalement global. Vous
devrait savoir à quel point il est dangereux d'accéder au monde entier sans protection des
l'immuabilité, que vous n'avez pas car vous devez utiliser un modèle de type référence!
TL; DR
Vous ne faites pas MVVM de manière java dans SwiftUI. Et la manière Swift-y de le faire n'est pas nécessaire
pour le faire, il est déjà intégré.
J'espère que plus de développeurs verront cela car cela semblait être une question populaire.
la source
Ci-dessous une approche qui fonctionne pour moi. Testé avec de nombreuses solutions démarrées avec Xcode 11.1.
Le problème provient de la façon dont EnvironmentObject est injecté dans la vue, schéma général
c'est-à-dire, à la première vue créée, au deuxième objet environnement créé, au troisième objet environnement injecté dans la vue
Ainsi, si j'ai besoin de créer / configurer un modèle de vue dans le constructeur de vues, l'objet environnement n'y est pas encore présent.
Solution: séparez tout et utilisez l'injection de dépendance explicite
Voici à quoi cela ressemble dans le code (schéma générique)
Il n'y a aucun compromis ici, car ViewModel et EnvironmentObject sont, par conception, des types de référence (en fait
ObservableObject
), donc je passe ici et là uniquement des références (aka pointeurs).la source