Swiftui - Como inicializar um observouObject usando um ambienteobjeto como parâmetro?

9

Não tenho certeza se esse é um antipadrão neste admirável mundo SwiftUI em que vivemos, mas basicamente tenho um @EnvironmentObject com algumas informações básicas do usuário salvas, que meus pontos de vista podem chamar.

Eu também tenho um @ObservedObject que possui alguns dados necessários para esta exibição.

Quando a exibição aparecer, desejo usar esse @EnvironmentObject para inicializar o @ObservedObject:

struct MyCoolView: View { 

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

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

Infelizmente, não consigo chamar a variável de ambiente até depois da inicialização:

"Não é possível usar o membro da instância 'userData' no inicializador de propriedades; os inicializadores de propriedades são executados antes que 'self' esteja disponível."

Eu posso ver algumas rotas possíveis adiante, mas todas elas se parecem com hacks. Como devo abordar isso?

snarik
fonte
Talvez você possa tentar adicionar um costume inità estrutura.
Nayem
Eu tentei isso e recebi um erro um tanto estranho: Property wrappers are not yet supported on local properties Basicamente, estou dizendo que não posso criar um @ObservedObject em um método init.
snarik

Respostas:

9

Aqui está a abordagem (a IMO mais simples):

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
fonte
Isto é perfeito. O MyCoolView era, na verdade, um filho de uma exibição em 'casa' onde eu declarei o ObservedObject. Obrigado!
snarik
Mas e se você quiser manipular os userData no ViewObject sem que um ViewObject totalmente novo seja criado a cada vez?
BobiSad 22/02
0

em vez de criar uma subvisão, você pode adicionar um inicializador fictício ao seu "ViewObject"para que você possa chamá-lo antes de chamar o 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 o registro eu não testei

Aleyam
fonte
0

Aqui está uma maneira fácil de fazer isso:

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

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

Com este ajudante que faz funcionar:

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