@Environment در SwiftUI — چیست، مفاهیم کلیدی و مکانیزم

نویسنده: IT Sectr منتشر شده: 2026-06-25 زمان مطالعه: 8 دقیقه

@Environment در SwiftUI — property wrapper برای خواندن مقادیر از محیط سیستم که به طور خودکار در سلسله‌مراتب View پخش می‌شوند. این مؤلفه دسترسی به طرح رنگ، locale، اندازه فونت، managedObjectContext و ده‌ها پارامتر سیستمی دیگر را فراهم می‌کند. بر اساس Apple Developer Documentation (2025)، @Environment تضمین می‌کند که هر تغییری در مقدار محیط باعث بازترسیم تمام Viewهای مشترک می‌شود و به‌روزرسانی واکنش‌گرای رابط را بدون فراخوانی دستی فراهم می‌کند.

نکات کلیدی

  • @Environment — property wrapper برای خواندن مقادیر محیط سیستم SwiftUI
  • طرح رنگ، locale و اندازه فونت — مقادیر سیستمی پرکاربرد
  • تغییر هر محیطی باعث بازترسیم خودکار Viewهای مشترک می‌شود
  • کلیدهای سفارشی امکان ایجاد مقادیر محیطی خود را از طریق EnvironmentKey فراهم می‌کنند
  • @Environment — فقط خواندنی؛ @EnvironmentObject — برای نوشتن

@Environment در SwiftUI چیست؟

@Environment — یک property wrapper SwiftUI است که برای خواندن مقادیر از محیط سیستم طراحی شده است. محیط یک ظرف سلسله‌مراتبی از مقادیر است که SwiftUI به طور خودکار از Viewهای والد به فرزندان منتشر می‌کند. هر مقدار محیط با یک کلید — نوعی منطبق بر پروتکل EnvironmentKey — شناسایی می‌شود.

مکانیزم محیط شبیه تزریق وابستگی (dependency injection) در سطح فریمورک است: سیستم مجموعه‌ای از مقادیر از پیش تعریف‌شده را ارائه می‌دهد — طرح رنگ (روشن/تاریک)، locale، اندازه فونت، managedObjectContext برای Core Data، dismiss برای بستن صفحه و بسیاری دیگر. Viewای که @Environment را با کلید مشخصی اعلام کرده است، به طور خودکار مقدار فعلی را دریافت می‌کند و در صورت تغییر آن بازترسیم می‌شود.

معماری محیط SwiftUI بر اساس پروتکل EnvironmentValues — ساختاری حاوی تمام مقادیر سیستمی — استوار است. هر مقدار به عنوان یک ویژگی از این ساختار با getter و setter ذخیره می‌شود. @Environment از key path برای دسترسی به ویژگی خاص استفاده می‌کند: @Environment(\.colorScheme) — دسترسی به طرح رنگ، @Environment(\.locale) — دسترسی به locale.

@Environment به عنوان Property Wrapper

Property wrapper @Environment دو مکانیزم کلیدی را پیاده‌سازی می‌کند: خواندن مقدار از محیط و اشتراک در تغییرات آن. هنگام ایجاد View، SwiftUI از تمام ویژگی‌های @Environment عبور می‌کند و آنها را به مقادیر متناظر از زمینه فعلی متصل می‌کند. اگر View والد مقدار را از طریق modifier .environment() تغییر دهد، تمام Viewهای فرزندی که این مقدار را می‌خوانند به طور خودکار بازترسیم می‌شوند.

ویژگی مهم: @Environment از مقادیر اختیاری پشتیبانی می‌کند. اگر مقداری در سلسله‌مراتب تنظیم نشده باشد، مقدار پیش‌فرض تعریف‌شده در EnvironmentKey برگردانده می‌شود. برای کلیدهای سیستمی، مقدار پیش‌فرض همیشه منطقی است — برای مثال، طرح رنگ پیش‌فرض .light. برای کلیدهای سفارشی، برنامه‌نویس خود مقدار پیش‌فرض را در متد defaultValue پروتکل EnvironmentKey تعیین می‌کند.

swift
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 (\.locale) شامل تنظیمات منطقه‌ای کاربر برای قالب‌بندی تاریخ‌ها، اعداد و ارزها است.

برای Core Data از managedObjectContext (\.managedObjectContext) استفاده می‌شود — زمینه‌ای که از طریق محیط از persistence container منتقل می‌شود. برای پیمایش، dismiss (\.dismiss) برای بستن صفحه فعلی و isPresented (\.isPresented) برای نماهای modal در دسترس هستند. برای تقویم و منطقه زمانی — به ترتیب 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 در مقابل @EnvironmentObject

با وجود نام‌های مشابه، @Environment و @EnvironmentObject وظایف متفاوتی را حل می‌کنند. @Environment مقادیر سیستمی یا سفارشی ثبت‌شده از طریق EnvironmentKey را می‌خواند. @EnvironmentObject — یک property wrapper برای ObservableObject است که از طریق محیط بر اساس نوع، بدون کلید صریح، منتقل می‌شود.

@EnvironmentObject برای تزریق وابستگی استفاده می‌شود: View والد یک شی (مثلاً ViewModel) ایجاد می‌کند و آن را از طریق modifier .environmentObject() به Viewهای فرزند منتقل می‌کند. Viewهای فرزند آن را از طریق @EnvironmentObject دریافت می‌کنند و می‌توانند هم ویژگی‌های آن را بخوانند و هم تغییر دهند. @Environment اما — فقط خواندنی برای مقادیر سیستمی است و بازخورد را پشتیبانی نمی‌کند.

پارامتر@Environment@EnvironmentObject
کاربردمقادیر سیستمی و سفارشیتزریق ObservableObject
کلیدKey path EnvironmentValuesبر اساس نوع شی
نوشتنفقط خواندنیخواندن و نوشتن
مقدار سفارشیاز طریق EnvironmentKeyاز طریق کلاس ObservableObject
مقدار پیش‌فرضدارد (defaultValue)ندارد (باید ارسال شود)

در عمل: از @Environment برای دسترسی به پارامترهای سیستمی (تم، locale، اندازه فونت) و تنظیمات سفارشی که در زمان اجرا تغییر نمی‌کنند استفاده کنید. از @EnvironmentObject برای انتقال ViewModel یا سرویس از طریق سلسله‌مراتب View زمانی که نیاز به تغییر وضعیت از مؤلفه‌های فرزند دارید استفاده کنید.

نمونه کدهای @Environment

ایجاد یک مقدار سفارشی محیط را بررسی می‌کنیم. برای این کار باید ساختاری مطابق با پروتکل EnvironmentKey تعریف کنید و EnvironmentValues را با یک ویژگی جدید گسترش دهید. این امکان را فراهم می‌کند که تنظیمات تم یا پارامترهای برنامه را بدون props از طریق کل درخت 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("حالت تاریک فعال")
                    .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 را از طریق modifier .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("ذخیره") { dismiss() }
            }
            .navigationTitle("Edit Profile")
        }
    }
}

این مثال استفاده عملی از dismiss — نمونه DismissAction از محیط را نشان می‌دهد. فراخوانی dismiss() به عنوان تابع، صفحه modal را می‌بندد یا NavigationLink را برمی‌گرداند. تنها شرط این است که View باید به صورت modal ارائه شده باشد یا در داخل 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 از modifier .environment() مستقیماً در کد Preview استفاده کنید: ThemedView().environment(\.colorScheme, .dark). این امکان بررسی بصری حالت‌های مختلف محیط را فراهم می‌کند.

خلاصه

  • @Environment — property wrapper برای خواندن مقادیر محیط سیستم SwiftUI از طریق key path
  • طرح رنگ، locale، اندازه فونت و managedObjectContext — پرکاربردترین مقادیر سیستمی
  • تغییر محیط باعث بازترسیم خودکار تمام Viewهای مشترک می‌شود
  • EnvironmentKey سفارشی امکان گسترش محیط برنامه با تنظیمات سراسری را فراهم می‌کنند
  • @Environment — فقط خواندنی؛ @EnvironmentObject — برای ObservableObject با قابلیت نوشتن
  • Modifier .environment() مقدار را برای Viewهای فرزند در سلسله‌مراتب تنظیم می‌کند
  • استفاده کنید @Environment برای پارامترهای سیستمی، @EnvironmentObject — برای ViewModel و سرویس‌ها

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید