J'ai une vue SwiftUI qui prend un EnvironmentObject appelé appModel
. Il lit ensuite la valeur appModel.submodel.count
dans sa méthode body
. Je m'attends à ce que cela lie ma vue à la propriété count
sur submodel
afin qu'elle s'affiche à nouveau lorsque la propriété est mise à jour, mais cela ne semble pas se produire.
Est-ce un bug? Sinon, quelle est la manière idiomatique de lier des vues aux propriétés imbriquées des objets d'environnement dans SwiftUI?
Plus précisément, mon modèle ressemble à ceci ...
class Submodel: ObservableObject {
@Published var count = 0
}
class AppModel: ObservableObject {
@Published var submodel: Submodel = Submodel()
}
Et ma vue ressemble à ceci ...
struct ContentView: View {
@EnvironmentObject var appModel: AppModel
var body: some View {
Text("Count: \(appModel.submodel.count)")
.onTapGesture {
self.appModel.submodel.count += 1
}
}
}
Lorsque j'exécute l'application et clique sur l'étiquette, la propriété count
augmente mais l'étiquette ne se met pas à jour.
Je peux résoudre ce problème en passant appModel.submodel
comme propriété de ContentView
, mais j'aimerais éviter de le faire si possible.
Les modèles imbriqués ne fonctionnent pas encore dans SwiftUI, mais vous pouvez faire quelque chose comme ça
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()
}
}
}
Fondamentalement, votre AppModel
intercepte l'événement à partir de Submodel
et l'envoie à la vue
Éditer:
Si vous n'avez pas besoin que SubModel
soit une classe, vous pouvez essayer quelque chose comme ceci:
struct Submodel{
var count = 0
}
class AppModel: ObservableObject {
@Published var submodel: Submodel = Submodel()
}
Les trois ViewModels peuvent communiquer et se mettre à jour
// 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
}
Merci Sorin pour la solution Combine.