#swift #swiftui #environmentobject
Вопрос:
Я понимаю, что EnvironmentObject
оболочку свойств можно использовать для передачи объектов в представления. У меня есть объект сеанса, который я передаю своим представлениям. Теперь у меня есть требование передать это в один из моих классов моделей (т. Е. Без представления). В идеале эта модель (получающая объект сеанса) создается как a StateObject
.
struct CreditDetailsView: View {
@EnvironmentObject var session: Session
@StateObject var transactionsModel = TransactionsModel(token: session.token)
Приведенный выше код не будет работать (понятно), потому что:
cannot use instance member 'session' within property initializer; property initializers run before 'self' is available
Есть какие-нибудь предложения о том, как я могу перейти в сессию TransactionsModel
?
Ответ №1:
Попробуйте инициализировать объект состояния в .onAppear()
реквизите для дочернего представления, например так:
struct CreditDetailsView: View {
@EnvironmentObject var session: Session
@StateObject var transactionsModel: TransactionModel?
var body: some View {
SomeChildView()
.onAppear(perform: {
transactionModel = TransactionModel(token: session.token)
})
}
}
Таким образом, переменная инициализируется при отображении представления на экране. Не имеет большого значения, в какое дочернее представление вы добавляете onAppear
реквизит, если он отображается сразу же после того, как это сделает родитель.
Комментарии:
1. Спасибо! В другой ситуации я смог передать токен в части действия при нажатии кнопки. Поэтому я предполагаю, что подход, описанный вами выше, а также нажатие кнопки-это 2 примера того, как это работает.
2. Нет проблем, надеюсь, это вам поможет 🙂
3. Как бы вы передали ссылку на сам объект среды, а не только на одно из его свойств (в данном случае свойство токена)? Я пытался это сделать, и я получаю множество ошибок.
Ответ №2:
Это неправильный ответ. Пожалуйста, ознакомьтесь с выбранным ответом выше.
Вы можете получить доступ session
к объекту внутри init
. В этом случае transactionsModel
должно быть сделано, чтобы быть уже инициализированным любым способом.
@EnvironmentObject var session: Session
@StateObject var transactionsModel = TransitionalModel(token: "")
init() {
let token = self.session.token
_transactionsModel = StateObject(wrappedValue: TransitionalModel(token: token))
}
Хотя об этом не может быть и речи, я не уверен, что это хороший способ передать что-то между ними, которые выглядят так, будто находятся на разных уровнях зрения.
Комментарии:
1. На самом деле я не видел никакого кода, предоставляющего инициализацию в представлении. Но подумать только, ничто не мешает вам это сделать. спасибо, что указали на это. Я могу просто вызвать метод в модели и предоставить токен через init.
2. Относительно поставки чего-то внутри
init
. насколько я знаю, это обычная схема. Когда вам нужно передать какое-то значение в представление и вы хотите использовать его в качестве начального значения определенного @State/@StateObject, оно обычно используется именно так. В этом случае обычно используется назначенный инициал, чтобы получить значение извне.3. Среда недоступна в
View
методе ainit
. Это приведет к фатальной ошибке, из-за которой не удастся найти наблюдаемый объект такого типа.4. О. Я не проверял это. извините за неправильный ответ. Я помещу комментарий поверх ответа.
Ответ №3:
Лучший способ, который я нашел для этого (потому что у вас не может быть необязательного объекта состояния), — это:
struct CreditDetailsView: View {
@EnvironmentObject var session: Session
@StateObject var localModel = LocalModel()
var body: some View {
SomeChildView()
.onAppear {
localModel.transactionModel = TransactionModel(token: session.token)
}
}
class LocalModel: ObservableObject {
@Published transactionModel: TransactionModel?
}
}