Ответ
Используйте @EnvironmentObject для передачи общих данных состояния через несколько уровней иерархии представлений без явной передачи через инициализаторы каждого дочернего вида. Это идеально для глобального состояния приложения, такого как данные пользователя, настройки темы или менеджер аутентификации.
Пример использования:
// 1. Создайте ObservableObject
class UserSettings: ObservableObject {
@Published var isLoggedIn = false
}
// 2. Вставьте объект в окружение корневого вида
MyApp()
.environmentObject(UserSettings())
// 3. Получите доступ к объекту в любом дочернем виде
struct ContentView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
if settings.isLoggedIn {
HomeView()
} else {
LoginView()
}
}
}
Ключевые моменты:
- Для чего: Для данных, к которым нужен доступ из многих несвязанных частей приложения.
- Чего избегать: Не используйте для локального состояния, которое передается только на один уровень вниз — для этого подходит
@Bindingили@State. - Важно: Объект должен быть помечен как
ObservableObjectи добавлен в окружение с помощью модификатора.environmentObject()до его использования, иначе приложение упадет.
Ответ 18+ 🔞
А, ну это же та самая штука, когда тебе надо, чтобы какая-то хуйня была доступна всем и каждому в приложении, не таская её через все инициализаторы, как горячую картошку. @EnvironmentObject, блядь.
Представь: у тебя есть какая-то центральная контора, типа настроек пользователя или того, вошёл он или нет. И эта контора должна быть доступна и в самом верхнем виде, и где-нибудь в глубине пятого экрана, в каком-нибудь SettingsDetailView, куда ты провалился через три навигации и два таба.
Так вот, если ты будешь пихать этот объект через инициализаторы каждого вида — это пиздец, надоест, и код превратится в спагетти. А @EnvironmentObject решает это изящно, как гопник решает вопрос с парковкой.
Как это работает, на пальцах:
- Создаёшь главную контору. Это просто класс, который подписан на
ObservableObject. Внутри него объявляешь свойства с@Published— это чтобы все виды, которые на него подписаны, узнавали, когда там что-то поменялось.
// Это наша главная контора. Назовём её UserSettings.
class UserSettings: ObservableObject {
@Published var isLoggedIn = false // Вот, например, залогинен юзер или нет.
@Published var username = "Гость" // Имя какое-нибудь.
}
Код не трогаем, он святой.
- Пропихиваешь эту контору в "окружение" с самого верха. То есть, когда запускаешь своё приложение, ты как бы говоришь: "Так, ребята, вот этот объект
UserSettingsтеперь висит в воздухе, и любой, кто захочет, может до него дотянуться".
// Где-то в точке входа, например в самом App
@main
struct MyApp: App {
// Создаём экземпляр нашей конторы один раз
let settings = UserSettings()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(settings) // ВОТ! Пропихнули его в окружение для всех детей ContentView.
}
}
}
- В любом дочернем виде, даже самом глубоком, просто кричишь: "Дайте сюда эту контору!" И SwiftUI тебе её подаёт. Делается это через
@EnvironmentObject.
struct ContentView: View {
// Просто объявляешь переменную. SwiftUI сам найдёт в окружении
// объект типа UserSettings и подставит его сюда. Магия, блядь.
@EnvironmentObject var settings: UserSettings
var body: some View {
if settings.isLoggedIn {
HomeView() // Показываем домой
} else {
LoginView() // Или просим залогиниться
}
}
}
// А вот где-нибудь в глубине, в каком-нибудь ProfileView...
struct DeepNestedProfileView: View {
// И здесь точно так же! Тот же самый объект, та же самая память.
@EnvironmentObject var settings: UserSettings
var body: some View {
Text("Привет, (settings.username)!") // И всё работает.
Button("Выйти") {
settings.isLoggedIn = false // Меняем состояние для ВСЕХ видов разом.
}
}
}
Ключевые моменты, чтобы не обосраться:
- Для чего это? Для данных, которые нужны овердохуища видам в разных ветках иерархии. Глобальные настройки, данные юзера, состояние покупок — вот это всё.
- Чего НЕ делать? Не пихай туда всякую локальную хуйню, которая нужна только родителю и его прямому ребёнку. Для этого есть
@Bindingили@State. Не усложняй, ебать. - Главная опасность: Ты ОБЯЗАН добавить объект в окружение с помощью
.environmentObject()ДО того, как какой-либо вид попытается его прочитать через@EnvironmentObject. Если не добавишь — приложение пизданулось с крашем, и будешь искать, где же ты проёбся. Проверяй это в первую очередь, если что-то не работает.
Короче, инструмент мощный, но как молоток: можно гвоздь забить, а можно себе по ебалу получить. Используй с умом.