Swiftui: ¿cómo inicializo un objeto observado utilizando un objeto ambiental como parámetro?

9

No estoy seguro de si esto es un antipatrón en este nuevo y valiente mundo de SwiftUI en el que vivimos, pero esencialmente tengo un @EnvironmentObject con cierta información básica del usuario guardada en ella que mis vistas pueden llamar.

También tengo un @ObservedObject que posee algunos datos necesarios para esta vista.

Cuando aparece la vista, quiero usar ese @EnvironmentObject para inicializar el @ObservedObject:

struct MyCoolView: View { 

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

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

Desafortunadamente, no puedo llamar a self en la variable de entorno hasta después de la inicialización:

"No se puede usar el miembro de instancia 'userData' dentro del inicializador de propiedades; los inicializadores de propiedades se ejecutan antes de que 'self' esté disponible".

Puedo ver algunas rutas posibles hacia adelante, pero todas se sienten como hacks. ¿Cómo debería abordar esto?

snarik
fuente
Tal vez pueda intentar agregar una costumbre inita la estructura.
nayem
Intenté eso y obtuve un error un tanto extraño: Property wrappers are not yet supported on local properties básicamente dice que no puedo crear un @ObservedObject en un método init.
snarik

Respuestas:

9

Aquí está el enfoque (la OMI más simple):

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
fuente
Esto es perfecto. MyCoolView era en realidad un niño en una vista de 'hogar' donde declaraba el Objeto Observado. ¡Gracias!
snarik
Pero, ¿qué sucede si desea manipular los datos de usuario dentro de ViewObject sin crear un ViewObject completamente nuevo cada vez?
BobiSad
0

en lugar de crear una subvista, puede agregar un inicializador ficticio para "ViewObject"poder llamarlo antes de llamar al inicializador real

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

para el registro no lo he probado

Aleyam
fuente
0

Aquí hay una manera fácil de hacerlo:

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

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

Con este ayudante que lo hace funcionar:

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