
SwiftUIでは、状態(State)を管理する方法として @State や @ObservedObject、@StateObject など複数の仕組みが用意されています。
その中でも @StateObject は、ビューと一緒にオブジェクトのライフサイクルを管理したい時に使う非常に重要なプロパティラッパーです。
この記事では、@StateObject の基本的な意味から、使い方、@State との違い、ベストプラクティスまでわかりやすく解説します。
@StateObjectとは?
@StateObject は、ObservableObject に準拠したクラスのインスタンスを 「Viewの所有者として初期化・保持」 するためのプロパティラッパーです。
SwiftUIにおいて、ビューは再描画や再生成されることがありますが、@StateObject を使えば、そのたびに新しいインスタンスが作られることなく、1回だけ初期化されたオブジェクトが継続的に使われます。
具体例:カウントアプリ
以下は @StateObject を使ってカウントアップを管理するシンプルな例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import SwiftUI class CounterModel: ObservableObject { @Published var count = 0 } struct CounterView: View { @StateObject private var counter = CounterModel() var body: some View { VStack { Text("カウント: \(counter.count)") .font(.largeTitle) Button("カウントアップ") { counter.count += 1 } } } } |
この例では CounterModel が ObservableObject に準拠しており、ビューは @StateObject としてそれを保持します。
ボタンをタップすると count が更新され、それに応じてビューも自動的に更新されます。
アプリのエントリーポイントでの使い方(ベストプラクティス)
SwiftUIアプリで最もよく使われるパターンは、アプリの起動時に @StateObject を定義し、それを .environmentObject() で注入する方法です。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
@main struct MyApp: App { @StateObject private var appViewModel = AppViewModel() var body: some Scene { WindowGroup { RootView() .environmentObject(appViewModel) } } } |
そして、サブViewでは次のように受け取ることができます。
|
1 2 3 4 5 6 7 8 |
struct RootView: View { @EnvironmentObject var appViewModel: AppViewModel var body: some View { Text("現在のユーザー: \(appViewModel.username)") } } |
この方法のメリット
- Viewの再生成でモデルが初期化される心配がない
- どのViewからでも簡単にアクセスできる
- グローバルな状態管理に最適
つまり、アプリ全体で使いたいオブジェクトは、Appのエントリーポイントで @StateObject → .environmentObject という流れがベストです。
@Stateとの違いは?
SwiftUIにおける@Stateと@StateObjectは、どちらもViewの状態管理をするためのプロパティラッパーですが、対象や使いどころが異なります。
特に@StateObjectは、ObservableObjectを使ったより大きなデータの管理に向いています。
以下の表で違いを整理すると分かりやすいです。
| 比較 | @State | @StateObject |
|---|---|---|
| 対象 | 値型(Struct)などの単純な状態 | ObservableObject(クラス) |
| 初期化 | プロパティに直接値を代入 | ObservableObjectのインスタンスを生成 |
| 目的 | 単純な状態の管理 | 外部にまたがるオブジェクトのライフサイクル管理 |
| データ共有 | 他のViewと共有しづらい | 環境に渡して共有しやすい(.environmentObject) |
たとえば、ボタンのON/OFF状態などは @State で十分ですが、複数の画面で共通して使うユーザー情報や設定情報などは @StateObject にする方が適しています。
活用シーン
@StateObjectが効果的なのは、単なる一時的な状態管理ではなく、長期間保持すべきデータや複数画面での共有が必要なケースです。
具体的には次のような場面が考えられます。
- データモデルの保持(例:ユーザーデータ、アプリ設定など)
- ネットワークやAPIの状態管理(例:API呼び出しの結果を保持)
- アプリ全体で使う情報の保持(例:ログイン情報、言語設定)
- 子Viewで再生成されたくないオブジェクトの管理
注意点
@StateObjectを使う際には、便利な一方で誤用すると予期せぬ挙動を招くことがあります。
そのため、以下の点に気を付けましょう。
@StateObjectは「初期化」を担当する → 複数回初期化しないようにする- 子Viewでは
@ObservedObjectまたは@EnvironmentObjectを使うべき - クラスは必ず
ObservableObjectに準拠し、@Publishedでプロパティをマークする @StateObjectをViewの中でlet宣言にしない(更新できないため)
私がまさにそうでしたが、使い方がわかっておらず、色々な場所で@StateObjectを使って「初期化の重複」してしまうなどは初心者がつまずきやすいポイントです。
まとめ
@StateObjectはSwiftUIにおける状態管理の中でもクラスベースのデータをViewが所有・保持するための仕組みです。
@StateObjectは、Viewが所有するObservableObjectを初期化・管理するためのプロパティラッパー@Stateとは異なり、クラスベースの状態管理が可能- アプリのルート(
@main)で定義して.environmentObjectで渡すのがベストプラクティス - アプリ全体で状態を共有したい場合にとても便利
SwiftUIで状態管理をするうえで @StateObject は欠かせない存在です。
使い方をマスターすることで、アプリの構造がより明確で保守しやすくなりますよ!

