
SwiftUIで複数のView間で共通のデータを扱いたいときに便利なのが .environmentObject(_:) です。
特定のデータを親Viewから子Viewに一括で共有し、どこからでもリアクティブにアクセス・変更できる環境を構築できます。
この記事では .environmentObject(_:) の基本的な意味や使い方、主要な仕組み、活用シーンまでわかりやすく解説します。
.environmentObject(_:) とは?
.environmentObject(_:) は SwiftUI におけるモディファイアの一種です。
ObservableObject に準拠したデータモデル(ViewModelなど)を「環境値(Environment)」として下層のViewに共有するための仕組み。
つまり、親Viewで設定した共有データを、@EnvironmentObject を使って下位のViewで簡単に参照・更新できるようになります。
@ObservedObject のように明示的にプロパティを渡す必要がなく、Viewの階層をまたいでもスムーズにデータアクセスできるのが特徴です。
具体例:アプリ全体で共有するカウント
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import SwiftUI class CounterModel: ObservableObject { @Published var count = 0 } struct RootView: View { @StateObject private var model = CounterModel() var body: some View { VStack { Text("RootView内カウント: \(model.count)") ChildView() } .environmentObject(model) } } struct ChildView: View { @EnvironmentObject var model: CounterModel var body: some View { VStack { Text("ChildView内カウント: \(model.count)") Button("カウント+1") { model.count += 1 } } } } |
RootView が CounterModel のインスタンスを .environmentObject(_:) で提供しており、ChildView 側では @EnvironmentObject を使って同じインスタンスにアクセスしています。
カウントボタンを押すと count が更新され、それが親・子両方のViewに自動反映されます。
このように「明示的に渡さずとも階層をまたいで共有できる」点が .environmentObject(_:) の非常に便利な点です。
アプリ全体で使うクラスなどは.environmentObject(_:)を利用して渡します。
主要な構成要素とその意味
.environmentObject(_:) を活用するには、次の3つの構成要素がセットで必要です。
| 要素 | 役割 |
|---|---|
ObservableObject に準拠したデータモデル |
共有するデータそのもの。@Published でプロパティを更新可能に |
.environmentObject(model) モディファイア |
上位Viewでモデルを環境に登録 |
@EnvironmentObject プロパティラッパー |
下位Viewで共有モデルにアクセスするための宣言 |
これらをセットで構成することで、アプリ全体または複数の関連View間で状態を同期できます。
.environmentObject の指定の仕方
まずは ObservableObject に準拠したデータモデルを定義し、プロパティには @Published を付けて変更検知可能にします。
下記では、AppSettingsがObservableObjectに準拠したデータモデルに該当します。
|
1 2 3 4 |
class AppSettings: ObservableObject { @Published var isDarkMode: Bool = false } |
次に親Viewで .environmentObject(_:) を使って ViewModel を環境に登録します。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
@main struct MyApp: App { @StateObject private var settings = AppSettings() var body: some Scene { WindowGroup { RootView() .environmentObject(settings) } } } |
そして下位のViewでは @EnvironmentObject を使って呼び出します。
|
1 2 3 4 5 6 7 8 |
struct SettingsToggleView: View { @EnvironmentObject var settings: AppSettings var body: some View { Toggle("ダークモード", isOn: $settings.isDarkMode) } } |
このように.environmentObject(_:) を正しく使えば、View間で依存性注入を意識せずにモデルを一元管理できます。
.environmentObject の活用シーン
.environmentObject(_:) は以下のような場面で特に活用されます。
- アプリ全体で共通の設定(テーマ、ログイン状態など)を保持したいとき
- 複数View間で同じ ViewModel を共有したいとき(親 → 孫のように階層が深いとき)
- 複数の画面をまたいで状態を一貫して保ちたい(ナビゲーションの中でも同じ状態を使い続けたい)
- サイドメニューやタブバーなど共通コンポーネントにデータを渡したいとき
- テスト用のViewModelをアプリ全体に一括適用したいとき
状態管理が必要な SwiftUI アプリでは、@StateObject でモデルを初期化し、.environmentObject(_:) で配下Viewに渡す構成が定番です。
.environmentObject を使うときの注意点
便利な .environmentObject(_:) ですが、いくつかの注意点もあります。
@EnvironmentObjectの指定があるViewは、必ず.environmentObject(_:)で注入された環境内で動作する必要がある(そうでないとクラッシュ)- インスタンスは
@StateObjectなどでしっかり保持しておく(構築元が破棄されると参照切れになる) - Previewで使うときは
.environmentObject(...)を手動で補う必要がある(でないとクラッシュ)
|
1 2 3 4 5 6 7 |
struct SomeView_Previews: PreviewProvider { static var previews: some View { SomeView() .environmentObject(AppSettings()) // 忘れるとエラー } } |
私がアプリ開発を始めた当初、よく@EnvironmentObjectを注入し忘れて、アプリがクラッシュする状態に陥っていました笑
アプリがクラッシュする場合は、@EnvironmentObjectを注入し忘れてないか?を確認しましょう。
まとめ
今回は.environmentObject(_:)モディファイアを紹介しました。
.environmentObject(_:)は共通のObservableObjectを下位のViewに共有する仕組み@EnvironmentObjectを使えば明示的な引数なしで ViewModel にアクセス可能- アプリ全体の設定や状態共有、複数画面間の同期に最適
- Previewや依存関係の明示、注入忘れによるクラッシュに注意が必要
状態を一元管理しながら、複雑なデータの受け渡しをシンプルにしたいときに .environmentObject(_:) はめちゃくちゃ便利な機能です。
ぜひあなたのアプリにも取り入れてみてくださいね!
