Cómo decirle a SwiftUI vistas que se unan a ObservableObjects anidados

18

Tengo una vista SwiftUI que toma un objeto de entorno llamado appModel. Luego lee el valor appModel.submodel.counten su bodymétodo. Espero que esto se una a mi punto de vista de la propiedad countde submodelmanera que cuando se vuelve a renderizar, pero esto no parecen los cambios de propiedad a suceder.

¿Es esto un error? Y si no, ¿cuál es la forma idiomática de hacer que las vistas se unan a las propiedades anidadas de los objetos del entorno en SwiftUI?

Específicamente, mi modelo se ve así ...

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

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

Y mi punto de vista se ve así ...

struct ContentView: View {
  @EnvironmentObject var appModel: AppModel

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

Cuando ejecuto la aplicación y hago clic en la etiqueta, la countpropiedad aumenta pero la etiqueta no se actualiza.

Puedo arreglar esto pasando appModel.submodelcomo una propiedad a ContentView, pero me gustaría evitar hacerlo si es posible.

rjkaplan
fuente
También estoy diseñando mi aplicación así. Por lo general, tengo un objeto de aplicación global en el desarrollo de aplicaciones anteriores. ¿Alguien más piensa que este diseño de una clase súper "App" como variable de entorno se convertirá en una práctica estándar? También estaba considerando usar múltiples ObjectObjects pero ha sido difícil de mantener.
Michael Ozeryansky

Respuestas:

22

Los modelos anidados aún no funcionan en SwiftUI, pero podría hacer algo como esto

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()
        }
    } 
}

Básicamente tu AppModelcaptura el evento Submodely lo envía más lejos a la Vista

Editar:

Si no necesita SubModelser clase, entonces puede intentar algo como esto:

struct Submodel{
    var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()
}
Sorin Lica
fuente
Gracias, esto es útil! Cuando dice "Los modelos anidados aún no funcionan en SwiftUI", ¿sabe con certeza que están planificados?
rjkaplan
No estoy seguro, pero en mi opinión debería funcionar, también utilizo algo similar en mi proyecto, así que si encuentro un mejor enfoque, vendré con una edición
Sorin Lica el
@SorinLica ¿Debería Submodelser ObservableObject tipo?
Farhan Amjad
¡Esta funcionando! ¡Impresionante solución!
Md Shahed Hossain
1

Los tres ViewModels pueden comunicarse y actualizar

// 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
}

Gracias Sorin por la solución combinada.

zdravko zdravkin
fuente
¿Podrías actualizar el código? tiene muchos errores de compilación
DevB2F
-2

Parece un insecto. Cuando actualizo el xcode a la última versión, funciona correctamente cuando se vincula a ObservableObjects anidados

norains
fuente
¿Puedes aclarar en qué versión de xcode estás trabajando actualmente? Actualmente tengo Xcode 11.0 y tengo este problema. He tenido problemas para actualizar a 11.1, no pasará como el 80% completo.
Michael Ozeryansky