Comment dire aux vues SwiftUI de se lier à des objets observables imbriqués


18

J'ai une vue SwiftUI qui prend un EnvironmentObject appelé appModel. Il lit ensuite la valeur appModel.submodel.countdans sa bodyméthode. Je pense que cela lie mon avis à la propriété countsur submodelafin qu'il re-Renders lorsque les mises à jour de propriété, mais cela ne semble pas se produire.

Est-ce un bug? Et sinon, quelle est la manière idiomatique de faire en sorte que les vues soient liées 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 countpropriété augmente mais l'étiquette ne se met pas à jour.

Je peux résoudre ce problème en passant en appModel.submodeltant que propriété ContentView, mais j'aimerais éviter de le faire si possible.


Je conçois également mon application comme ça. J'ai généralement un objet App global dans le développement d'applications passé. Est-ce que quelqu'un d'autre pense que cette conception d'une super classe "App" comme variable d'environnement deviendra une pratique standard? J'envisageais également d'utiliser plusieurs EnvironmentObjects, mais cela a été difficile à maintenir.
Michael Ozeryansky du

Réponses:


22

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 AppModelcapture l'événement Submodelet l'envoyez à la vue

Éditer:

Si vous n'avez pas besoin SubModeld'être en classe, vous pouvez essayer quelque chose comme ceci:

struct Submodel{
    var count = 0
}

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

Merci, c'est utile! Lorsque vous dites "Les modèles imbriqués ne fonctionnent pas encore dans SwiftUI", savez-vous avec certitude qu'ils sont planifiés?
rjkaplan

Je ne suis pas sûr, mais à mon avis, cela devrait fonctionner, j'utilise également quelque chose de similaire dans mon projet, donc si je trouve une meilleure approche, je viendrai avec un montage
Sorin Lica

@SorinLica Doit Submodelêtre de ObservableObject type?
Farhan Amjad

Ça marche! Super solution!
Md Shahed Hossain

1

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.


Pourriez-vous mettre à jour le code? il contient de nombreuses erreurs de compilation
DevB2F

-2

Cela ressemble à un bug. Lorsque je mets à jour le xcode vers la dernière version, il fonctionne correctement lors de la liaison à des ObservableObjects imbriqués


Pouvez-vous clarifier la version de xcode sur laquelle vous vous trouvez actuellement et qui fonctionne? J'ai actuellement Xcode 11.0 et je rencontre ce problème. J'ai eu du mal à obtenir la mise à niveau vers 11.1, elle ne passera pas à 80%.
Michael Ozeryansky
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.