Swiftui - Jak zainicjować zaobserwowany obiekt przy użyciu obiektu środowiska jako parametru?


9

Nie jestem pewien, czy jest to antypattern w tym odważnym nowym świecie SwiftUI, w którym żyjemy, ale zasadniczo mam @EnvironmentObject z zapisanymi podstawowymi informacjami dla użytkownika, które mogą wywoływać moje poglądy.

Mam również @ObservedObject, który posiada niektóre dane wymagane dla tego widoku.

Kiedy pojawi się widok, chcę użyć tego @EnvironmentObject do zainicjowania @ObservedObject:

struct MyCoolView: View { 

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

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

Niestety nie mogę wywołać self w zmiennej środowiskowej, dopóki nie zostanie zainicjowana:

„Nie można użyć elementu członkowskiego„ userData ”instancji w inicjalizatorze właściwości; inicjatory właściwości są uruchamiane, zanim będzie dostępne„ self ”.”

Widzę kilka możliwych dróg naprzód, ale wszystkie wydają się hackami. Jak mam do tego podejść?


Może możesz spróbować dodać niestandardową initstrukturę.
— nayem

Próbowałem tego i dostałem nieco dziwny błąd: Property wrappers are not yet supported on local properties Zasadniczo to powiedzenie, że nie mogę utworzyć @ObservedObject w metodzie init.
— snarik

Odpowiedzi:


9

Oto podejście (najprostsze 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)")
    }
}

To jest doskonałe. MyCoolView był w rzeczywistości dzieckiem widoku „domowego”, w którym zadeklarowałem obiekt ObservedObject. Dzięki!
— snarik

Ale co, jeśli chcesz manipulować danymi użytkownika w ViewObject bez tworzenia nowego ViewObject za każdym razem?
— BobiSad

0

zamiast tworzyć widok podrzędny, możesz dodać do niego atrapę inicjatora, aby "ViewObject"móc go wywołać przed wywołaniem prawdziwego inicjalizatora

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

dla przypomnienia, nie testowałem tego


0

Oto prosty sposób:

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

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

Dzięki temu pomocnikowi, który sprawia, że ​​działa:

struct Observe<T: ObservableObject, V: View>: View {
    @ObservedObject var obj: T
    let content: (T) -> V
    var body: some View { content(obj) }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.