@Environment в SwiftUI — что это, ключевые понятия и механизм

Автор: IT Sectr Опубликовано: 2026-06-25 Время чтения: 8 мин

@Environment в SwiftUI — property wrapper для чтения значений из системного окружения, автоматически распространяемых по иерархии View. Компонент предоставляет доступ к цветовой схеме, локали, размеру шрифта, managedObjectContext и десяткам других системных параметров. По данным Apple Developer Documentation (2025), @Environment гарантирует, что любое изменение значения окружения вызывает перерисовку всех подписанных View, обеспечивая реактивное обновление интерфейса без ручных вызовов.

Главное

  • @Environment — property wrapper для чтения значений системного окружения SwiftUI
  • Цветовая схема, локаль и размер шрифта — часто используемые системные значения
  • Изменение любого окружения вызывает автоматическую перерисовку подписанных View
  • Кастомные ключи позволяют создавать собственные значения окружения через EnvironmentKey
  • @Environment — только для чтения; @EnvironmentObject — для записи

Что такое @Environment в SwiftUI?

@Environment — это property wrapper SwiftUI, предназначенный для чтения значений из системного окружения. Окружение — это иерархический контейнер значений, который SwiftUI автоматически распространяет от родительских View к дочерним. Каждое значение окружения идентифицируется ключом — типом, соответствующим протоколу EnvironmentKey.

Механизм окружения напоминает dependency injection на уровне фреймворка: система предоставляет предопределённый набор значений — цветовая схема (light/dark), локаль, размер шрифта, managedObjectContext для Core Data, dismiss для закрытия экрана и многие другие. View, объявившая @Environment с определённым ключом, автоматически получает текущее значение и перерисовывается при его изменении.

Архитектура окружения SwiftUI основана на протоколе EnvironmentValues — структуре, содержащей все системные значения. Каждое значение хранится как свойство этой структуры с getter и setter. @Environment использует key path для доступа к конкретному свойству: @Environment(\.colorScheme) — доступ к цветовой схеме, @Environment(\.locale) — к локали.

@Environment как Property Wrapper

Property wrapper @Environment реализует два ключевых механизма: чтение значения из среды и подписку на его изменения. При создании View SwiftUI проходится по всем @Environment-свойствам и связывает их с соответствующими значениями из текущего контекста. Если родительская View изменяет значение через модификатор .environment(), все дочерние View, читающие это значение, автоматически перерисовываются.

Важная особенность: @Environment поддерживает опциональные значения. Если значение не установлено в иерархии, возвращается значение по умолчанию, определённое в EnvironmentKey. Для системных ключей значение по умолчанию всегда разумно — например, цветовая схема по умолчанию .light. Для кастомных ключей разработчик сам определяет default-значение в методе defaultValue протокола EnvironmentKey.

swift
struct EnvironmentReaderView: View {
    @Environment(\.colorScheme) var colorScheme
    @Environment(\.locale) var locale
    @Environment(\.sizeCategory) var sizeCategory

    var body: some View {
        VStack {
            Text("Current scheme: \(colorScheme == .dark ? "Dark" : "Light")")
            Text("Locale: \(locale.identifier)")
            Text("Font size: \(sizeCategory)")
        }
    }
}

В примере View читает три системных значения окружения. При изменении colorScheme — например, пользователь включил тёмную тему в настройках — View автоматически перерисовывается с новым значением. Аналогично при смене региона или размера шрифта (Dynamic Type). View не нужно подписываться на уведомления или вызывать refresh — SwiftUI управляет этим автоматически.

Системные значения окружения

SwiftUI предоставляет десятки системных значений окружения, охватывающих различные аспекты интерфейса и поведения. Цветовая схема (\ .colorScheme) — одно из самых востребованных значений, позволяющее адаптировать интерфейс под светлую и тёмную тему. Локаль (\ .locale) содержит региональные настройки пользователя для форматирования дат, чисел и валют.

Для Core Data используется managedObjectContext (\ .managedObjectContext) — контекст, передаваемый через окружение из persistence container. Для навигации доступны dismiss (\ .dismiss) для закрытия текущего экрана и isPresented (\ .isPresented) для модальных представлений. Для календаря и часового пояса — calendar и timeZone соответственно.

Key PathТипНазначение
\.colorSchemeColorSchemeСветлая или тёмная тема
\.localeLocaleРегиональные настройки
\.sizeCategoryContentSizeCategoryРазмер шрифта Dynamic Type
\.managedObjectContextNSManagedObjectContextКонтекст Core Data
\.dismissDismissActionЗакрытие экрана
\.calendarCalendarТекущий календарь
\.timeZoneTimeZoneЧасовой пояс
\.horizontalSizeClassUserInterfaceSizeClassГоризонтальный размер экрана

Для доступа к системным значениям используйте key path через точку: @Environment(\.dismiss) var dismiss. Компилятор проверяет существование key path в EnvironmentValues, поэтому ошибочный ключ вызовет ошибку на этапе сборки. Новые системные значения добавляются Apple с каждой версией iOS — актуальный список доступен в документации EnvironmentValues.

@Environment vs @EnvironmentObject

Несмотря на похожие названия, @Environment и @EnvironmentObject решают разные задачи. @Environment читает системные или кастомные значения, зарегистрированные через EnvironmentKey. @EnvironmentObject — это property wrapper для ObservableObject, передаваемого через окружение по типу, без явного ключа.

@EnvironmentObject используется для dependency injection: родительская View создаёт объект (например, ViewModel) и передаёт его дочерним View через модификатор .environmentObject(). Дочерние View получают его через @EnvironmentObject и могут как читать, так и изменять его свойства. @Environment же — только для чтения системных значений и не поддерживает обратную связь.

Параметр@Environment@EnvironmentObject
НазначениеСистемные и кастомные значенияObservableObject инъекция
КлючKey path EnvironmentValuesПо типу объекта
ЗаписьТолько чтениеЧтение и запись
Кастомное значениеЧерез EnvironmentKeyЧерез класс ObservableObject
Значение по умолчаниюЕсть (defaultValue)Нет (обязательно передать)

На практике: используйте @Environment для доступа к системным параметрам (тема, локаль, размер шрифта) и кастомным конфигурациям, которые не меняются в рантайме. Используйте @EnvironmentObject для передачи ViewModel или сервиса через иерархию View, когда требуется изменять состояние из дочерних компонентов.

Примеры кода @Environment

Рассмотрим создание кастомного значения окружения. Для этого нужно определить структуру, соответствующую протоколу EnvironmentKey, и расширить EnvironmentValues новым свойством. Это позволяет передавать конфигурацию темы или настройки приложения через всё дерево View без пропсы.

swift
struct AppThemeKey: EnvironmentKey {
    static let defaultValue: AppTheme = .system
}

extension EnvironmentValues {
    var appTheme: AppTheme {
        get { self[AppThemeKey.self] }
        set { self[AppThemeKey.self] = newValue }
    }
}

enum AppTheme { case system, light, dark }

Протокол EnvironmentKey требует реализации статического свойства defaultValue — значение, которое будет использоваться, если родительская View не установила кастомное окружение. Расширение EnvironmentValues добавляет вычисляемое свойство appTheme, используя subscript с ключом. После этого любая View может читать значение через @Environment(\.appTheme).

Использование @Environment с кастомным ключом

swift
struct ThemedView: View {
    @Environment(\.appTheme) var appTheme
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        VStack {
            if appTheme == .dark || (appTheme == .system && colorScheme == .dark) {
                Text("Dark mode active")
                    .foregroundStyle(.white)
                    .background(Color.black)
            } else {
                Text("Light mode active")
                    .foregroundStyle(.black)
                    .background(Color.white)
            }
        }
    }
}

struct ContentView: View {
    @State private var selectedTheme = AppTheme.system

    var body: some View {
        ThemedView()
            .environment(\.appTheme, selectedTheme)
    }
}

ThemedView читает два окружения: кастомное appTheme и системное colorScheme. Комбинация позволяет реализовать гибкую настройку темы: пользователь может выбрать «Светлая», «Тёмная» или «Системная» тема. Если выбрана системная — значение берётся из colorScheme, которое автоматически меняется при переключении темы в настройках iOS. Родительская View (ContentView) устанавливает значение appTheme через модификатор .environment().

Использование dismiss для закрытия экрана

swift
struct ModalView: View {
    @Environment(\.dismiss) var dismiss
    @State private var name = ""

    var body: some View {
        NavigationStack {
            Form {
                TextField("Your name", text: $name)
                Button("Save") { dismiss() }
            }
            .navigationTitle("Edit Profile")
        }
    }
}

Этот пример демонстрирует практическое использование dismiss — экземпляра DismissAction из окружения. Вызов dismiss() как функции закрывает модальный экран или возвращает NavigationLink. Единственное требование — View должна быть представлена модально или находиться внутри NavigationStack. dismiss автоматически определяется из контекста: если View открыта как sheet — закрывается sheet, если как popover — закрывается popover.

Часто задаваемые вопросы

Можно ли изменить значение @Environment из дочерней View?

Нет, @Environment предназначен только для чтения. Для изменения значений используйте @EnvironmentObject с ObservableObject или @Binding. Кастомные EnvironmentKey могут иметь setter в расширении, но изменение через него не триггерит обновление UI — это технически возможно, но не рекомендуется.

Чем @Environment отличается от @Binding?

@Binding создаёт двустороннюю связь с источником истины (State, StateObject, ObservableObject). @Environment — однонаправленное чтение из иерархического контекста. @Binding подходит для передачи данных в дочернюю View, @Environment — для доступа к системным или глобальным настройкам.

Как создать своё значение окружения?

Определите структуру, реализующую протокол EnvironmentKey со static defaultValue. Затем расширьте EnvironmentValues свойством с getter/setter через subscript[key]. После регистрации используйте @Environment(\.yourKey) для чтения и .environment(\.yourKey, value) для установки.

Какие значения окружения доступны в SwiftUI?

SwiftUI предоставляет более 50 системных значений: colorScheme, locale, sizeCategory, managedObjectContext, dismiss, calendar, timeZone, horizontalSizeClass, verticalSizeClass, accessibilityEnabled, layoutDirection, legibilityWeight и другие. Полный список в документации EnvironmentValues.

Работает ли @Environment в Preview?

Да, @Environment работает в Preview, но значения по умолчанию могут отличаться от симулятора. Для тестирования в Preview используйте модификатор .environment() прямо в Preview-коде: ThemedView().environment(\.colorScheme, .dark). Это позволяет визуально проверять различные состояния окружения.

Итоги

  • @Environment — property wrapper для чтения значений системного окружения SwiftUI по key path
  • Цветовая схема, локаль, размер шрифта и managedObjectContext — наиболее востребованные системные значения
  • Изменение окружения вызывает автоматическую перерисовку всех подписанных View
  • Кастомные EnvironmentKey позволяют расширять окружение приложения глобальными настройками
  • @Environment — только для чтения; @EnvironmentObject — для ObservableObject с записью
  • Модификатор .environment() устанавливает значение для дочерних View в иерархии
  • Используйте @Environment для системных параметров, @EnvironmentObject — для ViewModel и сервисов

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также