Como dizer às exibições do SwiftUI para vincular a ObservableObjects aninhados

18

Eu tenho uma visualização SwiftUI que utiliza um EnvironmentObject chamado appModel. Em seguida, ele lê o valor appModel.submodel.countem seu bodymétodo. Espero que este se ligar meu ponto de vista para a propriedade countde submodelmodo que ele processa novamente quando as atualizações de propriedade, mas isso não parece acontecer.

Isso é um inseto? E se não, qual é a maneira idiomática de vincular exibições a propriedades aninhadas de objetos de ambiente no SwiftUI?

Especificamente, meu modelo fica assim ...

class Submodel: ObservableObject {
  @Published var count = 0
}

class AppModel: ObservableObject {
  @Published var submodel: Submodel = Submodel()
}

E minha visão é assim ...

struct ContentView: View {
  @EnvironmentObject var appModel: AppModel

  var body: some View {
    Text("Count: \(appModel.submodel.count)")
      .onTapGesture {
        self.appModel.submodel.count += 1
      }
  }
}

Quando executo o aplicativo e clico no rótulo, a countpropriedade aumenta, mas o rótulo não é atualizado.

Eu posso consertar isso passando appModel.submodelcomo uma propriedade para ContentView, mas gostaria de evitar fazer isso, se possível.

rjkaplan
fonte
Também estou projetando meu aplicativo assim. Normalmente, tenho um objeto App global no desenvolvimento de aplicativos anteriores. Alguém mais acha que esse design de uma classe super "App" como variável de ambiente se tornará uma prática padrão? Eu também estava pensando em usar vários EnvironmentObjects, mas isso tem sido difícil de manter.
Michael Ozeryansky

Respostas:

22

Modelos aninhados ainda não funcionam no SwiftUI, mas você pode fazer algo assim

class Submodel: ObservableObject {
    @Published var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()

    var anyCancellable: AnyCancellable? = nil

    init() {
        anyCancellable = submodel.objectWillChange.sink { (_) in
            self.objectWillChange.send()
        }
    } 
}

Basicamente, você AppModelcaptura o evento Submodele o envia para o View

Editar:

Se você não precisa SubModelser de classe, pode tentar algo assim:

struct Submodel{
    var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()
}
Sorin Lica
fonte
Obrigado, isso é útil! Quando você diz "Modelos aninhados ainda não funcionam no SwiftUI", você tem certeza de que eles estão planejados?
Rjkaplan 16/10/19
Eu não tenho certeza, mas na minha opinião ele deve funcionar, eu também usar algo semelhante no meu proj, por isso, se eu vou encontrar uma melhor abordagem que eu vou com uma edição
Sorin Lica
@SorinLica Deve Submodelser do ObservableObject tipo?
Farhan Amjad
Está funcionando! Solução incrível!
Md Shahed Hossain
1

Todos os três ViewModels podem se comunicar e atualizar

// First ViewModel
class FirstViewModel: ObservableObject {
var facadeViewModel: FacadeViewModels

facadeViewModel.firstViewModelUpdateSecondViewModel()
}

// Second ViewModel
class SecondViewModel: ObservableObject {

}

// FacadeViewModels Combine Both 

import Combine // so you can update thru nested Observable Objects

class FacadeViewModels: ObservableObject { 
lazy var firstViewModel: FirstViewModel = FirstViewModel(facadeViewModel: self)
  @Published var secondViewModel = secondViewModel()
}

var anyCancellable = Set<AnyCancellable>()

init() {
firstViewModel.objectWillChange.sink {
            self.objectWillChange.send()
        }.store(in: &anyCancellable)

secondViewModel.objectWillChange.sink {
            self.objectWillChange.send()
        }.store(in: &anyCancellable)
}

func firstViewModelUpdateSecondViewModel() {
     //Change something on secondViewModel
secondViewModel
}

Obrigado Sorin pela solução Combine.

zdravko zdravkin
fonte
Você pode atualizar o código? tem muitos erros de compilação
DevB2F 25/03
-2

Parece bug. Quando atualizo o xcode para a versão mais recente, ele funciona corretamente quando vinculado a ObservableObjects aninhados

norains
fonte
Você pode esclarecer em qual versão do xcode você trabalha atualmente? Atualmente, tenho o Xcode 11.0 e enfrenta esse problema. Eu tive problemas para atualizar para o 11.1, ele não passará 80% completo.
Michael Ozeryansky 22/10/19