@Environment у SwiftUI — property wrapper за читање вредности из системског окружења, аутоматски распрострањених кроз хијерархију View. Компонента пружа приступ шеми боја, локалу, величини фонта, managedObjectContext-у и десетинама других системских параметара. Према Apple Developer Documentation (2025), @Environment гарантује да било која промена вредности окружења изазива прецртавање свих пријављених View-ова, обезбеђујући реактивно ажурирање интерфејса без ручних позива.
Главно
@Environment — је SwiftUI property wrapper намењен за читање вредности из системског окружења. Окружење је хијерархијски контејнер вредности који SwiftUI аутоматски распростире од родитељских View-ова ка дечјим. Свака вредност окружења идентификује се кључем — типом усклађеним са протоколом EnvironmentKey.
Механизам окружења подсећа на dependency injection на нивоу framework-а: систем обезбеђује предефинисани скуп вредности — шему боја (light/dark), локал, величину фонта, managedObjectContext за Core Data, dismiss за затварање екрана и многе друге. View који је декларисао @Environment са одређеним кључем аутоматски добија тренутну вредност и прецртава се при њеној промени.
Архитектура окружења SwiftUI се заснива на протоколу EnvironmentValues — структури која садржи све системске вредности. Свака вредност се чува као својство ове структуре са getter-ом и setter-ом. @Environment користи key path за приступ одређеном својству: @Environment(\.colorScheme) — приступ шеми боја, @Environment(\.locale) — локалу.
Property wrapper @Environment имплементира два кључна механизма: читање вредности из окружења и пријаву на његове промене. Приликом креирања View-а, SwiftUI пролази кроз сва @Environment својства и повезује их са одговарајућим вредностима из тренутног контекста. Ако родитељски View промени вредност преко модификатора .environment(), сви дечји View-ови који читају ту вредност се аутоматски прецртавају.
Важна карактеристика: @Environment подржава опционе вредности. Ако вредност није постављена у хијерархији, враћа се подразумевана вредност дефинисана у EnvironmentKey. За системске кључеве, подразумевана вредност је увек разумна — на пример, шема боја подразумевано .light. За прилагођене кључеве програмер сам одређује подразумевану вредност у методи defaultValue протокола EnvironmentKey.
struct EnvironmentReaderView: View {
@Environment(\.colorScheme) var colorScheme
@Environment(\.locale) var locale
@Environment(\.sizeCategory) var sizeCategory
var body: some View {
VStack {
Text("Тренутна шема: \(colorScheme == .dark ? "Dark" : "Light")")
Text("Locale: \(locale.identifier)")
Text("Величина фонта: \(sizeCategory)")
}
}
}
У примеру View чита три системске вредности окружења. При промени colorScheme — на пример, корисник је укључио тамну тему у подешавањима — View се аутоматски прецртава са новом вредношћу. Слично при промени региона или величине фонта (Dynamic Type). View не мора да се пријављује на обавештења или да позива освежавање — SwiftUI управља овим аутоматски.
SwiftUI обезбеђује десетине системских вредности окружења, покривајући различите аспекте интерфејса и понашања. Шема боја (\.colorScheme) — једна од најтраженијих вредности, која омогућава прилагођавање интерфејса светлом и тамном темом. Локал (\.locale) садржи регионална подешавања корисника за форматирање датума, бројева и валута.
За Core Data користи се managedObjectContext (\.managedObjectContext) — контекст који се преноси кроз окружење из persistence container-а. За навигацију су доступни dismiss (\.dismiss) за затварање тренутног екрана и isPresented (\.isPresented) за модалне приказе. За календар и временску зону — calendar и timeZone.
| Key Path | Тип | Намена |
|---|---|---|
| \.colorScheme | ColorScheme | Светла или тамна тема |
| \.locale | Locale | Регионална подешавања |
| \.sizeCategory | ContentSizeCategory | Величина фонта Dynamic Type |
| \.managedObjectContext | NSManagedObjectContext | Core Data контекст |
| \.dismiss | DismissAction | Затварање екрана |
| \.calendar | Calendar | Тренутни календар |
| \.timeZone | TimeZone | Временска зона |
| \.horizontalSizeClass | UserInterfaceSizeClass | Хоризонтална величина екрана |
За приступ системским вредностима користите key path кроз тачку: @Environment(\.dismiss) var dismiss. Компајлер проверава постојање key path-а у EnvironmentValues, па ће погрешан кључ изазвати грешку у фази компилације. Нове системске вредности Apple додаје са сваком верзијом iOS-а — актуелни списак доступан је у документацији EnvironmentValues.
Упркос сличним називима, @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 за приступ системским параметрима (тема, локал, величина фонта) и прилагођеним конфигурацијама које се не мењају у runtime-у. Користите @EnvironmentObject за пренос ViewModel-а или сервиса кроз хијерархију View-ова када је потребно мењати стање из дечјих компоненти.
Размотримо креирање прилагођене вредности окружења. За то је потребно дефинисати структуру усклађену са протоколом EnvironmentKey и проширити EnvironmentValues новим својством. Ово омогућава пренос конфигурације теме или подешавања апликације кроз цело стабло View-ова без props-а.
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).
struct ThemedView: View {
@Environment(\.appTheme) var appTheme
@Environment(\.colorScheme) var colorScheme
var body: some View {
VStack {
if appTheme == .dark || (appTheme == .system && colorScheme == .dark) {
Text("Тамни режим активан")
.foregroundStyle(.white)
.background(Color.black)
} else {
Text("Светли режим активан")
.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().
struct ModalView: View {
@Environment(\.dismiss) var dismiss
@State private var name = ""
var body: some View {
NavigationStack {
Form {
TextField("Your name", text: $name)
Button("Сачувај") { dismiss() }
}
.navigationTitle("Edit Profile")
}
}
}
Овај пример демонстрира практичну употребу dismiss — инстанце DismissAction из окружења. Позив dismiss() као функције затвара модални екран или враћа NavigationLink. Једини захтев — View мора бити приказан модално или се налазити унутар NavigationStack-а. dismiss се аутоматски одређује из контекста: ако је View отворен као sheet — затвара се sheet, ако као popover — затвара се popover.
Често постављана питања
Не, @Environment је намењен само за читање. За промену вредности користите @EnvironmentObject са ObservableObject или @Binding. Прилагођени EnvironmentKey могу имати setter у проширењу, али промена преко њега не покреће ажурирање UI-ја — то је технички могуће, али се не препоручује.
@Binding ствара двосмерну везу са извором истине (State, StateObject, ObservableObject). @Environment — једносмерно читање из хијерархијског контекста. @Binding је погодан за пренос података у дечји View, @Environment — за приступ системским или глобалним подешавањима.
Дефинишите структуру која имплементира протокол EnvironmentKey са static defaultValue. Затим проширите EnvironmentValues својством са getter-ом/setter-ом преко subscript[key]. Након регистрације користите @Environment(\.yourKey) за читање и .environment(\.yourKey, value) за постављање.
SwiftUI обезбеђује преко 50 системских вредности: colorScheme, locale, sizeCategory, managedObjectContext, dismiss, calendar, timeZone, horizontalSizeClass, verticalSizeClass, accessibilityEnabled, layoutDirection, legibilityWeight и друге. Комплетан списак у документацији EnvironmentValues.
Да, @Environment ради у Preview-у, али подразумеване вредности могу да се разликују од симулатора. За тестирање у Preview-у користите модификатор .environment() директно у Preview коду: ThemedView().environment(\.colorScheme, .dark). Ово омогућава визуелну проверу различитих стања окружења.
Завршни преглед
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође