So weisen Sie SwiftUI-Ansichten an, an verschachtelte ObservableObjects zu binden

18

Ich habe eine SwiftUI-Ansicht, die ein aufgerufenes EnvironmentObject aufnimmt appModel. Es liest dann den Wert appModel.submodel.countin seiner bodyMethode. Ich erwarte , dass dies meine Ansicht nach auf die Eigenschaft binden , countauf , submodelso dass es wieder macht , wenn die Eigenschaft Updates, aber dies nicht zu geschehen scheint.

Ist das ein Fehler? Und wenn nicht, wie können Ansichten idiomatisch an verschachtelte Eigenschaften von Umgebungsobjekten in SwiftUI gebunden werden?

Insbesondere sieht mein Modell so aus ...

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

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

Und meine Ansicht sieht so aus ...

struct ContentView: View {
  @EnvironmentObject var appModel: AppModel

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

Wenn ich die App starte und auf das Etikett countklicke, erhöht sich die Eigenschaft, aber das Etikett wird nicht aktualisiert.

Ich kann dies beheben, indem ich appModel.submodelals Eigentum an übergeben werde ContentView, aber ich möchte dies nach Möglichkeit vermeiden.

rjkaplan
quelle
Ich entwerfe meine App auch so. Normalerweise habe ich in der vergangenen App-Entwicklung ein globales App-Objekt. Glaubt sonst noch jemand, dass dieses Design einer Super-App-Klasse als Umgebungsvariable zur Standardpraxis wird? Ich habe auch überlegt, mehrere EnvironmentObjects zu verwenden, aber das war schwer zu pflegen.
Michael Ozeryansky

Antworten:

22

Verschachtelte Modelle funktionieren in SwiftUI noch nicht, aber Sie könnten so etwas tun

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

Grundsätzlich AppModelfängt man das Ereignis ab Submodelund sendet es weiter an die Ansicht

Bearbeiten:

Wenn Sie nicht SubModelklasse sein müssen, können Sie auch Folgendes ausprobieren:

struct Submodel{
    var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()
}
Sorin Lica
quelle
Danke, das ist hilfreich! Wenn Sie sagen "Verschachtelte Modelle funktionieren in SwiftUI noch nicht", wissen Sie sicher, dass sie geplant sind?
rjkaplan
Ich bin mir nicht sicher, aber meiner Meinung nach sollte es funktionieren, ich verwende auch etwas Ähnliches in meinem Projekt. Wenn ich also einen besseren Ansatz finde, werde ich mit einer Bearbeitung kommen
Sorin Lica
@SorinLica Sollte Submodelsein ObservableObject Typ?
Farhan Amjad
Es funktioniert! Tolle Lösung!
Md Shahed Hossain
1

Alle drei ViewModels können kommunizieren und aktualisieren

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

Vielen Dank, dass Sie Sorin für Combine Lösung.

zdravko zdravkin
quelle
Könnten Sie den Code aktualisieren? Es hat viele Compilerfehler
DevB2F
-2

Es sieht aus wie ein Käfer. Wenn ich den xcode auf die neueste Version aktualisiere, funktioniert er beim Binden an verschachtelte ObservableObjects ordnungsgemäß

Norains
quelle
Können Sie klären, auf welcher Xcode-Version Sie gerade arbeiten? Ich habe derzeit Xcode 11.0 und habe dieses Problem. Ich hatte Probleme beim Upgrade auf 11.1, es wird nicht zu 80% abgeschlossen sein.
Michael Ozeryansky