SwiftUIの@Environmentは、システム環境から値を読み取るためのproperty wrapperであり、View術を自動的に伝播します。このコンポーネントは、カラースキーム、ロケール、フォントサイズ、managedObjectContext、その他多数のシステムパラメータへのアクセスを提供します。Apple Developer Documentation (2025)によれば、@Environmentは、環境値の変更がサブスクライブされたすべてのViewの再描画を引き起こし、マニュアルなコールなしでリアクティブなインタフェース更新を実現することを保証します。
メインポイント
@Environmentは、システム環境から値を読み取るために設計されたSwiftUIのproperty wrapperです。環境は、SwiftUIが親Viewから子Viewへ自動的に伝播する値の階層的コンテナです。それぞれの環境値は、EnvironmentKeyプロトコルに従うタイプであるキーによって識別されます。
環境の仕組みは、フレームワークレベルでの依存性インジェクションに類似しています。システムは事前定義された値のセットを提供します — カラースキーム(ライト/ダーク)、ロケール、フォントサイズ、Core Data用のmanagedObjectContext、画面を閉じるためのdismiss、その他多数。特定のキーで@Environmentを宣言したViewは、現在の値を自動的に取得し、それが変わったときに再描画されます。
SwiftUI環境アーキテクチャは、EnvironmentValuesプロトコルに基づいています — すべてのシステム値を含む構造体です。それぞれの値は、getterとsetterを持つこの構造体のプロパティとして格納されます。@Environmentは、特定のプロパティにアクセスするためにkey pathを使用します: @Environment(\.colorScheme) — カラースキームへのアクセス、@Environment(\.locale) — ロケールへのアクセス。
Property wrapper @Environmentは、2つの主な仕組みを実装しています: 環境から値を読み取り、その変化にサブスクライブすること。Viewが作成されると、SwiftUIはすべての@Environmentプロパティを経由し、現在のコンテキストから対応する値にリンクします。親Viewが.environment()修飾子を通じて値を変更すると、その値を読むすべての子Viewが自動的に再描画されます。
重要な機能: @Environmentはオプショナル値をサポートしています。階層で値が設定されていない場合、EnvironmentKeyで定義されたデフォルト値が返されます。システムキーの場合、デフォルト値はいつも合理的です — 例えば、デフォルトのカラースキームは.lightです。カスタムキーの場合、開発者がEnvironmentKeyプロトコルのdefaultValueメソッドでデフォルト値を定義します。
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が3つのシステム環境値を読み取っています。colorSchemeが変わったとき — 例えば、ユーザーが設定でダークモードを有効にしたとき — Viewは新しい値で自動的に再描画されます。同様に、地域やフォントサイズ(Dynamic Type)が変わった場合も同じです。Viewは通知にサブスクライブしたり、refreshをコールする必要がありません — SwiftUIがこれを自動的に管理します。
SwiftUIは、インタフェースと動作のさまざまな要素をカバーする数十のシステム環境値を提供しています。カラースキーム (\.colorScheme)は、ライトモードとダークモードにインタフェースを適応させることができる、もっともよく使われる値の1つです。ロケール (\.locale)には、日付、数値、通貨のフォーマットのためのユーザーのローカル設定が含まれます。
Core Dataでは、managedObjectContext (\.managedObjectContext)が使用されます — パーシステンスコンテナから環境を通じて渡されるコンテキストです。ナビゲーションには、現在の画面を閉じるための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。コンパイラはEnvironmentValuesでのkey pathの存在を確認するため、間違ったキーはコンパイルタイムエラーを引き起こします。Appleは、iOSのバージョンごとに新しいシステム値を追加しています — 完全なリストはEnvironmentValuesドキュメンテーションで確認できます。
同じような名前にもかかわらず、@Environmentと@EnvironmentObjectは異なる目的を持ちます。@Environmentは、EnvironmentKeyを通じて登録されたシステムまたはカスタム値を読み取ります。@EnvironmentObjectは、明示的なキーなしで、タイプによって環境を通じて渡されるObservableObjectのproperty wrapperです。
@EnvironmentObjectは依存性インジェクションに使用されます: 親Viewがオブジェクト(例: ViewModel)を作成し、.environmentObject()修飾子を通じて子Viewに渡します。子Viewは@EnvironmentObjectを通じて受け取り、そのプロパティを読み取ったり変更したりできます。一方、@Environmentはシステム値のための読み取り専用であり、フィードバックをサポートしていません。
| パラメータ | @Environment | @EnvironmentObject |
|---|---|---|
| 目的 | システムおよびカスタム値 | ObservableObjectインジェクション |
| キー | EnvironmentValuesのkey path | オブジェクトのタイプによる |
| 書き込み | 読み取り専用 | 読み取りと書き込み |
| カスタム値 | EnvironmentKeyを通じて | ObservableObjectクラスを通じて |
| デフォルト値 | あり (defaultValue) | なし (渡す必要があり) |
実務上: システムパラメータ(モード、ロケール、フォントサイズ)およびランタイムで変わらないカスタム設定にアクセスするには@Environmentを使用します。子コンポーネントから状態を変更する必要がある場合、View階層を通じてViewModelまたはサービスを渡すには@EnvironmentObjectを使用します。
カスタム環境値の作成を見てみましょう。これには、EnvironmentKeyプロトコルに従う構造体を定義し、EnvironmentValuesを新しいプロパティで拡張する必要があります。これにより、プロパティを使わずに、アプリケーション設定やテーマ設定をViewツリー全体に渡すことができます。
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を拡張すると、キーでsubscriptを使用して、計算プロパティappThemeが追加されます。これにより、どの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("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は2つの環境を読み取ります: カスタムのappThemeとシステムのcolorScheme。この組み合わせにより、軽柔なテーマ設定が可能になります: ユーザーは、ライト、ダーク、システムのテーマを選択できます。システムが選択された場合、値はcolorSchemeから取得され、iOS設定でテーマが切り替えられると自動的に変更されます。親View (ContentView)は.environment()修飾子を通じてappTheme値を設定します。
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は読み取り専用です。値を変更するには、ObservableObjectを伴う@EnvironmentObjectか@Bindingを使用してください。カスタムEnvironmentKeysには拡張でsetterを持てますが、これを通じての変更はUI更新をトリガーしません — 技術的には可能ですが、推奨されません。
@Bindingは、真実のソース(State、StateObject、ObservableObject)への双方向接続を作ります。@Environmentは、階層コンテキストからの単方向読み取りです。@Bindingは子Viewへデータを渡すのに適し、@Environmentはシステムまたはグローバル設定にアクセスするのに適しています。
静的なdefaultValueを持つEnvironmentKeyプロトコルを実装する構造体を定義します。その後、subscript[key]を使ったgetter/setterでプロパティを持つようにEnvironmentValuesを拡張します。登録後、読み取りには@Environment(\.yourKey)、設定には.environment(\.yourKey, value)を使用します。
SwiftUIは50以上のシステム値を提供しています: colorScheme, locale, sizeCategory, managedObjectContext, dismiss, calendar, timeZone, horizontalSizeClass, verticalSizeClass, accessibilityEnabled, layoutDirection, legibilityWeight、その他。完全なリストはEnvironmentValuesドキュメンテーションで確認できます。
はい、@EnvironmentはPreviewで動作しますが、デフォルト値がシミュレータと異なる場合があります。Previewでテストするには、Previewコードで直接.environment()修飾子を使用します: ThemedView().environment(\.colorScheme, .dark)。これにより、異なる環境状態を視的に確認できます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。