Swiftui - Как инициализировать наблюдаемый объект, используя объект окружающей среды в качестве параметра?

9

Я не уверен, является ли это антипаттерном в этом прекрасном новом мире SwiftUI, в котором мы живем, но по сути у меня есть объект @EnvironmentObject с некоторой базовой пользовательской информацией, которая может быть вызвана моими представлениями.

У меня также есть @ObservedObject, которому принадлежат некоторые данные, необходимые для этого представления.

Когда появится представление, я хочу использовать этот @EnvironmentObject для инициализации @ObservedObject:

struct MyCoolView: View { 

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

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

К сожалению, я не могу вызвать себя для переменной окружения, пока после инициализации:

«Невозможно использовать экземпляр экземпляра userData в инициализаторе свойства; инициализаторы свойства запускаются до того, как станет доступным« self ».»

Я вижу несколько возможных маршрутов, но все они чувствуют себя как хаки. Как мне подойти к этому?

snarik
источник
Может быть, вы можете попробовать добавить кастом initв структуру.
Наем
Я попробовал это и получил несколько странную ошибку: по Property wrappers are not yet supported on local properties сути, это говорит о том, что я не могу создать @ObservedObject в методе init.
snarik

Ответы:

9

Вот подход (самый простой ИМО):

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
источник
Это потрясающе. MyCoolView был фактически дочерним по отношению к «домашнему» представлению, где я объявил ObservedObject. Спасибо!
snarik
Но что, если вы хотите манипулировать userData внутри ViewObject, не создавая каждый раз совершенно новый ViewObject?
BobiSad
0

вместо создания подпредставления вы можете добавить фиктивный инициализатор в свой, "ViewObject"чтобы вы могли вызвать его до вызова реального инициализатора

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

для записи я не проверял

Aleyam
источник
0

Вот простой способ сделать это:

struct MyCoolView: View {
    @EnvironmentObject var userData: UserData

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

С этим помощником, который заставляет его работать:

struct Observe<T: ObservableObject, V: View>: View {
    @ObservedObject var obj: T
    let content: (T) -> V
    var body: some View { content(obj) }
}
ccwasden
источник