Swiftui - Wie initialisiere ich ein beobachtetes Objekt mit einem Umgebungsobjekt als Parameter?

9

Ich bin mir nicht sicher, ob dies ein Gegenmuster in dieser schönen neuen SwiftUI-Welt ist, in der wir leben, aber im Wesentlichen habe ich ein @EnvironmentObject mit einigen grundlegenden Benutzerinformationen, die meine Ansichten aufrufen können.

Ich habe auch ein @ObservedObject, das einige Daten besitzt, die für diese Ansicht erforderlich sind.

Wenn die Ansicht angezeigt wird, möchte ich dieses @EnvironmentObject verwenden, um das @ObservedObject zu initialisieren:

struct MyCoolView: View { 

    @EnvironmentObject userData: UserData
    @ObservedObject var viewObject: ViewObject = ViewObject(id: self.userData.UID)  

    var body: some View { 
            Text("\(self.viewObject.myCoolProperty)")
    } 
}

Leider kann ich die Umgebungsvariable erst nach der Initialisierung aufrufen:

"Das Instanzmitglied 'userData' kann im Eigenschaftsinitialisierer nicht verwendet werden. Eigenschaftsinitialisierer werden ausgeführt, bevor 'self' verfügbar ist."

Ich kann ein paar mögliche Routen vorwärts sehen, aber sie fühlen sich alle wie Hacks an. Wie soll ich das angehen?

Snarik
quelle
Vielleicht können Sie versuchen init, der Struktur einen Benutzer hinzuzufügen .
Nayem
Ich habe das versucht und einen etwas seltsamen Fehler erhalten: Property wrappers are not yet supported on local properties Grundsätzlich kann ich kein @ObservedObject in einer init-Methode erstellen.
Snarik

Antworten:

9

Hier ist der Ansatz (die einfachste IMO):

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

    var body: some View {
        MyCoolInternalView(ViewObject(id: self.userData.UID))
    }
}

struct MyCoolInternalView: View {
    @EnvironmentObject var userData: UserData
    @ObservedObject var viewObject: ViewObject

    init(_ viewObject: ViewObject) {
        self.viewObject = viewObject
    }

    var body: some View {
            Text("\(self.viewObject.myCoolProperty)")
    }
}
Asperi
quelle
Dies ist perfekt. Die MyCoolView war eigentlich ein Kind in einer 'Home'-Ansicht, in der ich das ObservedObject deklariert habe. Vielen Dank!
Snarik
Was aber, wenn Sie die Benutzerdaten in ViewObject bearbeiten möchten, ohne dass jedes Mal ein völlig neues ViewObject erstellt wird?
BobiSad
0

Anstatt eine Unteransicht zu erstellen, können Sie einen Dummy-Initialisierer hinzufügen, "ViewObject"damit Sie ihn aufrufen können, bevor Sie den echten Initialisierer aufrufen

struct MyCoolView: View { 

    @EnvironmentObject userData: UserData
    @ObservedObject var viewObject: ViewObject

    init() {
        viewObject = ViewObject()
        defer {
            viewObject = ViewObject(id: self.userData.UID)
        }
    }

    var body: some View { 
            Text("\(self.viewObject.myCoolProperty)")
    } 
}

Für die Aufzeichnung habe ich es nicht getestet

Aleyam
quelle
0

Hier ist ein einfacher Weg dorthin:

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

    var body: some View {
        Observe(obj: ViewObject(id: userData.UID)) { viewObject in
             Text("\(viewObject.myCoolProperty)")
        }
    }
}

Mit diesem Helfer funktioniert es:

struct Observe<T: ObservableObject, V: View>: View {
    @ObservedObject var obj: T
    let content: (T) -> V
    var body: some View { content(obj) }
}
ccwasden
quelle