Estou procurando criar um EnvironmentObject que possa ser acessado pelo modelo de exibição (não apenas pela exibição).
O objeto Environment controla os dados da sessão do aplicativo, por exemplo, logon, token de acesso etc., esses dados serão passados para os modelos de exibição (ou classes de serviço, quando necessário) para permitir a chamada de uma API para transmitir dados desse EnvironmentObjects.
Eu tentei passar o objeto de sessão para o inicializador da classe de modelo de exibição da exibição, mas obtive um erro.
como posso acessar / transmitir o EnvironmentObject no modelo de exibição usando o SwiftUI?
Consulte o link para testar o projeto: https://gofile.io/?c=vgHLVx
Respostas:
Eu escolho não ter um ViewModel. (Talvez seja hora de um novo padrão?)
Eu configurei meu projeto com uma
RootView
e algumas exibições filho. Eu configurei o meuRootView
com umApp
objeto como o EnvironmentObject. Em vez de o ViewModel acessar modelos, todas as minhas visualizações acessam as classes no aplicativo. Em vez de o ViewModel determinar o layout, a hierarquia da visualização determina o layout. Ao fazer isso na prática para alguns aplicativos, descobri que meus pontos de vista são pequenos e específicos. Como uma simplificação excessiva:Nas minhas visualizações, inicializo um
MockApp
que é uma subclasse deApp
. O MockApp inicializa os inicializadores designados com o objeto Mocked. Aqui, o UserService não precisa ser ridicularizado, mas a fonte de dados (por exemplo, NetworkManagerProtocol).fonte
app.userService.logout()
.userService
deve ser privado e acessado apenas de dentro da classe do aplicativo. O código acima deve ter a seguinte aparência:Button(action: { app.logout() })
e a função de logoff será chamada diretamenteuserService.logout()
.Você não deveria. É um equívoco comum que o SwiftUI funcione melhor com o MVVM.
MVVM não tem lugar no SwfitUI. Você está perguntando se pode empurrar um retângulo para
ajuste uma forma de triângulo. Não caberia.
Vamos começar com alguns fatos e trabalhar passo a passo:
ViewModel é um modelo no MVVM.
O MVVM não leva em consideração o tipo de valor (por exemplo, não existe tal coisa em java).
Um modelo de tipo de valor (modelo sem estado) é considerado mais seguro que a referência
modelo de tipo (modelo com estado) no sentido de imutabilidade.
Agora, o MVVM exige que você configure um modelo de forma que, sempre que ele for alterado,
atualiza a visualização de alguma maneira predeterminada. Isso é conhecido como ligação.
Sem ligação, você não terá uma boa separação de preocupações, por exemplo; refatorando
modelo e estados associados e mantendo-os separados da vista.
Estas são as duas coisas que a maioria dos desenvolvedores de MVVM para iOS falha:
O iOS não possui mecanismo de "ligação" no sentido tradicional de java.
Alguns simplesmente ignoram a ligação e acham que chamar um objeto ViewModel
resolve automagicamente tudo; alguns introduziriam o RX baseado em KVO e
complicar tudo quando o MVVM deve simplificar as coisas.
modelo com estado é muito perigoso
porque o MVVM coloca muita ênfase no ViewModel, muito pouco no gerenciamento de estado
e disciplinas gerais no gerenciamento do controle; a maioria dos desenvolvedores acaba
pensar que um modelo com estado usado para atualizar a vista é reutilizável e
testável .
é por isso que o Swift introduz o tipo de valor em primeiro lugar; um modelo sem
Estado.
Agora, sua pergunta: você pergunta se seu ViewModel pode ter acesso ao EnvironmentObject (EO)?
Você não deveria. Como no SwiftUI, um modelo em conformidade com o View automaticamente
referência ao OE. Por exemplo;
Espero que as pessoas possam apreciar como o SDK compacto é projetado.
No SwiftUI, o MVVM é automático . Não há necessidade de um objeto ViewModel separado
que se liga manualmente à exibição que requer uma referência de EO passada para ele.
O código acima é MVVM. Por exemplo; um modelo com ligação para visualizar.
Mas como modelo é do tipo valor, em vez de refatorar o modelo e o estado como
Para visualizar o modelo, você refatora o controle (na extensão do protocolo, por exemplo).
Este é o SDK oficial que adapta o padrão de design ao recurso de idioma, em vez de apenas
aplicá-lo. Substância sobre a forma.
Olhe para a sua solução, você precisa usar o singleton, que é basicamente global. Vocês
deve saber o quão perigoso é acessar global em qualquer lugar sem a proteção de
imutabilidade, que você não possui porque precisa usar o modelo de tipo de referência!
TL; DR
Você não faz MVVM em java no SwiftUI. E a maneira rápida de fazer isso não é necessária
para isso, já está embutido.
Espero que mais desenvolvedores vejam isso, pois essa parecia uma pergunta popular.
fonte
Abordagem fornecida abaixo que funciona para mim. Testado com muitas soluções iniciadas no Xcode 11.1.
O problema teve origem na maneira como o EnvironmentObject é injetado na vista, esquema geral
ou seja, na primeira visão criada, no segundo objeto de ambiente criado, no terceiro objeto de ambiente injetado na vista
Portanto, se eu precisar criar / configurar o modelo de exibição no construtor de exibição, o objeto de ambiente ainda não está presente.
Solução: divida tudo e use injeção de dependência explícita
Aqui está como ele aparece no código (esquema genérico)
Não há nenhuma troca aqui, porque ViewModel e EnvironmentObject são, por design, tipos de referência (na verdade
ObservableObject
), então eu passo aqui e ali apenas referências (também conhecidas como ponteiros).fonte