Swiftui - Comment initialiser un objet observé en utilisant un objet environnement comme paramètre?

9

Je ne suis pas sûr que ce soit un contre-modèle dans ce nouveau monde SwiftUI courageux dans lequel nous vivons, mais essentiellement j'ai un @EnvironmentObject avec quelques informations utilisateur de base enregistrées que mes vues peuvent appeler.

J'ai également un @ObservedObject qui possède certaines données requises pour cette vue.

Lorsque la vue apparaît, je veux utiliser ce @EnvironmentObject pour initialiser le @ObservedObject:

struct MyCoolView: View { 

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

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

Malheureusement, je ne peux pas m'appeler sur la variable d'environnement avant l'initialisation:

"Impossible d'utiliser le membre d'instance 'userData' dans l'initialiseur de propriété; les initialiseurs de propriété s'exécutent avant que 'self' ne soit disponible."

Je peux voir quelques itinéraires possibles, mais ils se sentent tous comme des hacks. Comment dois-je aborder cela?

snarik
la source
Vous pouvez peut-être essayer d'ajouter une personnalisation inità la structure.
nayem
J'ai essayé cela et j'ai eu une erreur quelque peu étrange: Property wrappers are not yet supported on local properties Fondamentalement, il est impossible de créer un @ObservedObject dans une méthode init.
snarik

Réponses:

9

Voici l'approche (l'OMI la plus 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
la source
C'est parfait. Le MyCoolView était en fait un enfant d'une vue «home» où j'ai déclaré l'ObservedObject. Merci!
snarik
Mais que se passe-t-il si vous souhaitez manipuler les données utilisateur dans ViewObject sans qu'un ViewObject entièrement nouveau soit créé à chaque fois?
BobiSad
0

au lieu de créer une sous-vue, vous pouvez ajouter un initialiseur factice à votre "ViewObject"afin de pouvoir l'appeler avant d'appeler le véritable initialiseur

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

pour mémoire, je ne l'ai pas testé

Aleyam
la source
0

Voici un moyen simple d'y accéder:

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

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

Avec cet assistant qui le fait fonctionner:

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