Chcę utworzyć obiekt środowiska, do którego można uzyskać dostęp za pomocą modelu widoku (nie tylko widoku).
Obiekt Environment śledzi dane sesji aplikacji, np. LoggedIn, token dostępu itp., Dane te zostaną przekazane do modeli widoku (lub klas usług, jeśli to konieczne), aby umożliwić wywołanie interfejsu API w celu przekazania danych z tego obiektu ObjectObjects.
Próbowałem przekazać obiekt sesji do inicjalizatora klasy modelu widoku z widoku, ale wystąpił błąd.
jak mogę uzyskać dostęp / przekazać obiekt EnvironmentObject do modelu widoku za pomocą SwiftUI?
Zobacz link do projektu testowego: https://gofile.io/?c=vgHLVx
Odpowiedzi:
Nie chcę mieć ViewModel. (Może czas na nowy wzór?)
Skonfigurowałem swój projekt z
RootView
kilkoma widokami potomnymi. Konfiguracji i mojeRootView
zApp
obiektu jako EnvironmentObject. Zamiast ViewModel uzyskującego dostęp do modeli, wszystkie moje widoki uzyskują dostęp do klas w aplikacji. Zamiast ViewModel określającego układ, hierarchia widoku określa układ. Po zrobieniu tego w praktyce dla kilku aplikacji, stwierdziłem, że moje poglądy są niewielkie i szczegółowe. Jako nadmierne uproszczenie:W moich zapowiedziach inicjuję
MockApp
podklasęApp
. MockApp inicjuje wyznaczone inicjatory za pomocą obiektu Mocked. Tutaj UserService nie musi być wyśmiewany, ale źródło danych (tj. NetworkManagerProtocol) robi to.źródło
app.userService.logout()
.userService
powinny być prywatne i dostępne tylko z poziomu klasy aplikacji. Powyższy kod powinien wyglądać następująco:Button(action: { app.logout() })
funkcja wylogowania zadzwoni bezpośredniouserService.logout()
.Nie powinieneś To powszechne błędne przekonanie, że SwiftUI działa najlepiej z MVVM.
MVVM nie ma miejsca w SwfitUI. Pytasz, czy możesz przesunąć prostokąt
pasują do kształtu trójkąta. Nie pasowałoby.
Zacznijmy od kilku faktów i pracuj krok po kroku:
ViewModel to model w MVVM.
MVVM nie bierze pod uwagę typu wartości (np. Nie ma czegoś takiego w java).
Model typu wartości (model bez stanu) jest uważany za bezpieczniejszy niż referencyjny
model typu (model ze stanem) w sensie niezmienności.
Teraz MVVM wymaga skonfigurowania modelu w taki sposób, aby za każdym razem, gdy się zmieniał
aktualizuje widok w określony sposób. Jest to znane jako wiązanie.
Bez wiązania nie będziesz miał przyjemnego rozdziału problemów, np. refaktoryzacja
model i skojarzone stany oraz oddzielając je od widoku.
Są to dwie rzeczy, których zawodzi większość programistów iOS MVVM:
iOS nie ma mechanizmu „wiązania” w tradycyjnym sensie Java.
Niektórzy po prostu zignorują powiązanie i pomyślą o wywołaniu obiektu ViewModel
automagicznie rozwiązuje wszystko; niektórzy wprowadziliby Rx oparte na KVO i
komplikuj wszystko, gdy MVVM ma uprościć sprawę.
model ze stanem jest po prostu zbyt niebezpieczny
ponieważ MVVM kładzie zbyt duży nacisk na ViewModel, zbyt mało na zarządzanie stanem
oraz ogólne dyscypliny w zarządzaniu Kontrolą; większość programistów kończy
myślenie, że model ze stanem używanym do aktualizacji widoku jest wielokrotnego użytku i
testowalny .
dlatego Swift przede wszystkim wprowadza rodzaj wartości; model bez
stan.
Teraz pytanie: pytasz, czy Twój ViewModel może mieć dostęp do EnvironmentObject (EO)?
Nie powinieneś Ponieważ w SwiftUI automatycznie ma model zgodny z View
odniesienie do EO. Na przykład;
Mam nadzieję, że ludzie docenią projekt kompaktowego zestawu SDK.
W SwiftUI MVVM działa automatycznie . Nie ma potrzeby oddzielnego obiektu ViewModel
który ręcznie łączy się z widokiem, który wymaga przekazania do niego referencji EO.
Powyższy kod to MVVM. Na przykład; model z wiązaniem do wyświetlenia.
Ale ponieważ model jest typem wartości, więc zamiast refaktoryzować model i podać stan jako
zobacz model, refaktoryzujesz kontrolę (na przykład w rozszerzeniu protokołu).
Jest to oficjalny zestaw SDK, dostosowujący wzór projektowy do funkcji języka, a nie tylko
egzekwowanie tego. Substancja nad formą.
Spójrz na swoje rozwiązanie, musisz użyć singletona, który jest zasadniczo globalny. ty
powinien wiedzieć, jak niebezpieczny jest dostęp globalny w dowolnym miejscu bez ochrony
niezmienność, której nie masz, ponieważ musisz użyć modelu typu referencyjnego!
TL; DR
Nie wykonujesz MVVM w języku Java w SwiftUI. A szybki sposób na zrobienie tego nie jest potrzebny
aby to zrobić, jest już wbudowany.
Mam nadzieję, że więcej programistów to zobaczy, ponieważ wydawało się to popularnym pytaniem.
źródło
Poniżej podano podejście, które działa dla mnie. Testowane z wieloma rozwiązaniami rozpoczętymi w Xcode 11.1.
Problem pochodzi ze sposobu, w jaki wtłaczany jest widok EnvironmentObject, ogólny schemat
tzn. w pierwszym utworzonym widoku, w drugim utworzonym obiekcie środowiska, w trzecim obiekcie środowiska wstrzykiwanym do widoku
Dlatego jeśli muszę utworzyć / skonfigurować model widoku w konstruktorze widoku, obiekt środowiska jeszcze tam nie ma.
Rozwiązanie: rozbij wszystko na części i użyj jawnego zastrzyku zależności
Oto jak to wygląda w kodzie (schemat ogólny)
Nie ma tu żadnego kompromisu, ponieważ ViewModel i EnvironmentObject są z założenia typami referencyjnymi (tak naprawdę
ObservableObject
), więc przekazuję tu i tam tylko referencje (inaczej wskaźniki).źródło