@ObservedObject: 概要、動作方法と例

著者: IT Sectr 公開日: 2026-06-19 読了時間: 7 分

@ObservedObjectは、外部から渡されたObservableObjectインスタンスを監視するためのSwiftUIのProperty Wrapperです。@StateObjectとは異なり、@ObservedObjectはオブジェクトを作成せず、既存のオブジェクトの変更を購読します。Apple Developer Documentation(2025)によると、@ObservedObjectは親に属するデータを追跡する必要がある子ビューで使用されます。@ObservedObjectは、オブジェクトのライフサイクルを管理せずにリアクティブな接続を提供します。

重要なポイント

  • @ObservedObject — 所有権なしでObservableObjectを監視するためのProperty Wrapper
  • 作成なし — オブジェクトは親ビューまたは環境から渡されます
  • @Published — ObservableObject内のプロパティで、その変更をSwiftUIが追跡します
  • 再レンダリング — @Publishedプロパティが変更されると、SwiftUIは購読中のすべてのビューを更新します
  • @StateObjectと混同しないでください — @ObservedObjectは単一インスタンスを保証しません

SwiftUIの@ObservedObjectとは?

@ObservedObjectは、ビューをObservableObjectの変更に購読させるProperty Wrapperです。ObservableObjectはCombineフレームワークのプロトコルで、objectWillChangeパブリッシャーの実装を必要とします。@PublishedでマークされたプロパティがObservedObject内で変更されると、パブリッシャーがシグナルを送信し、SwiftUIは@ObservedObjectを通じて購読しているすべてのビューを再レンダリングします。

@ObservedObjectの主な特徴は所有権がないことです。ビューはオブジェクトの作成や破棄に責任を持ちません。オブジェクトは親ビューで(@StateObjectを介して)作成されるか、@EnvironmentObjectを介して注入されます。子ビューは変更を監視して更新を受け取るだけです。親でオブジェクトが置き換えられると、@ObservedObjectは新しいインスタンスに切り替わります。

@ObservedObjectはデータ共有シナリオに適しています:ユーザーモデル、共通設定、サーバー接続状態など。階層の異なるレベルにある複数のビューが同じデータを表示する必要がある場合、各ビューの@ObservedObjectは単一のソースに対して独立した一貫性のある購読を作成します。

@ObservedObject vs @StateObject: 主な違い

@ObservedObjectと@StateObjectの違いは、SwiftUIの面接で最もよく聞かれる質問の1つです。主なルール:@StateObjectはオブジェクトを作成して所有し、@ObservedObjectは既存のオブジェクトを監視します。このルールに違反すると、予期しないデータ損失や二重初期化が発生します。

特性@StateObject@ObservedObject
オブジェクト作成はい、ビュー初期化時いいえ、既成のものを受け取る
所有権現在のビュー親コンポーネント
単一インスタンスはい、ライフサイクル全体いいえ、置き換え可能
レンダリング時の再作成いいえ、保持される親に依存する
使用場所ルートビュー所有者子ビュー

@StateObjectはオブジェクトが一度作成され、ビュー構造の繰り返しの初期化を生き残ることを保証します。@ObservedObjectは外部からオブジェクトを受け取り、親構造の初期化ごとに再作成されます。親がオブジェクトに@StateObjectを使用している場合、子ビューは安全に@ObservedObjectを適用できます — オブジェクトは階層全体で一意になります。

@ObservedObjectが変更を追跡する仕組み

@ObservedObjectの追跡メカニズムはCombineとObservableObjectプロトコルに基づいています。初期化中、SwiftUIはobjectWillChangeパブリッシャーを呼び出します — オブジェクトは@Publishedプロパティを変更する前にシグナルを発行する必要があります。CombineはシグナルをSwiftUIの依存関係グラフに渡し、依存するすべてのビューを更新が必要としてマークします。これは値が変更される前に同期的に発生します。

swift
class WeatherService: ObservableObject {
    @Published var temperature: Double = 22.0
    @Published var city: String = "Moscow"
}

struct WeatherView: View {
    @ObservedObject var weather: WeatherService

    var body: some View {
        VStack {
            Text("\(weather.city)")
            Text("\(weather.temperature)°C")
        }
    }
}

リストでは、WeatherServiceは2つの@Publishedプロパティを持つObservableObjectです。WeatherViewは@ObservedObject var weather: WeatherServiceを宣言し、親からインスタンスを受け取ります。temperatureが変更されると、新しい値を設定する前にobjectWillChangeが発動し、SwiftUIがWeatherViewを再レンダリングして実際の気温が表示されます。購読はSwiftUIによって自動的に管理されるため、開発者がsinkやdisposeを呼び出す必要はありません。

@ObservedObjectの使用パターン

最初のパターンはイニシャライザを介したモデルの受け渡しです。親は@StateObjectを介してObservableObjectを作成し、子ビューに@ObservedObjectとして渡します。これは標準的な階層的データ転送であり、ルートビューがモデルのライフサイクルを管理し、すべてのネストされたコンポーネントが変更を購読します。

2番目のパターンはEnvironmentObjectで、SwiftUI環境を介した@ObservedObjectのグローバルバージョンです。オブジェクトはシーンまたはルートビューレベルで注入され、イニシャライザを介した明示的な受け渡しなしですべての子コンポーネントが自動的に利用できます。子ビュー内では、@EnvironmentObjectは@ObservedObjectと同様に動作しますが、環境からオブジェクトを受け取ります。

3番目のパターンは複数のObservableObjectの構成です。複雑なアプリケーションでは、ビューは複数のオブジェクトを監視できます:@ObservedObject var user: UserService、@ObservedObject var network: NetworkMonitor。これにより、サービス間で責任が分離され、各コンポーネントのテスタビリティが維持されます。

swift
struct DashboardView: View {
    @ObservedObject var user: UserViewModel
    @ObservedObject var network: NetworkMonitor

    var body: some View {
        VStack {
            Text("Welcome, \(user.name)")
            HStack {
                Circle()
                    .fill(network.isConnected ? Color.green : Color.red)
                    .frame(width: 10, height: 10)
            }
        }
    }
}

DashboardViewはUserViewModelとNetworkMonitorを監視します。各オブジェクトは自身のデータドメインを処理し、独立してビューに変更を通知します。ネットワークが切断されると、NetworkMonitorはisConnectedを変更し、SwiftUIはDashboardViewを再レンダリングしてインジケーターの色を更新します。ObservableObjectの構成は、SwiftUIアプリケーションでデータを整理するための推奨方法です。

@Published: ObservableObjectとSwiftUIの橋渡し

@PublishedはCombineのProperty Wrapperで、ObservableObject内のプロパティに自動的にパブリッシャーを追加します。@Publishedプロパティが変更されると、CombineはobjectWillChangeパブリッシャーを介してイベントを生成します。@ObservedObjectまたは@StateObjectを使用する際、SwiftUIはこのパブリッシャーを購読し、新しい値ごとにビューを再レンダリングします。

@Publishedは、オプショナル、コレクション、カスタム構造体を含むすべての型をサポートします。ただし、コレクション(配列、辞書)の場合、SwiftUIは参照の置き換えのみを追跡し、内容の変更は追跡しません。要素の追加や削除を検出するには、コレクション全体を再代入するか、手動のobjectWillChange.send()とともにObservableObjectを使用する必要があります。

重要な詳細:@PublishedはObservableObjectを実装するクラス内でのみ使用する必要があります。ObservableObjectの外部で@Publishedを使用すると、コンパイルエラーが発生します。また、@Publishedを遅延初期化プロパティ(lazy var)や計算プロパティに適用することはできません。

@ObservedObjectのよくある間違い

最も深刻な間違いは、オブジェクトを作成するために@ObservedObjectを使用することです。親ビューで@ObservedObject var model = UserViewModel()と記述すると、レンダリングのたびに新しいUserViewModelインスタンスが作成されます。データは失われ、@Publishedの購読は再作成されます。作成には常に@StateObjectを使用し、@ObservedObjectは既存のオブジェクトを受け取るためだけに使用してください。

2番目の間違いはメインスレッド外での@Publishedプロパティの変更です。ObservableObjectはCombineを使用しており、メインスレッド(main actor)での変更送信が必要です。バックグラウンドキューで@Publishedを変更すると、SwiftUIが不適切なタイミングでビューを再レンダリングし、競合状態を引き起こす可能性があります。更新にはDispatchQueue.main.asyncまたは@MainActorを使用してください。

3番目の問題は循環更新です。@Publishedの変更が再び@Publishedを変更する副作用を引き起こすと、無限の再レンダリングループが発生します。解決策:ガードフラグ(isUpdating)を使用するか、明確な責任範囲を持つ異なるObservableObjectにロジックを分離します。

よくある質問

@ObservedObjectはオプショナルにできますか?

はい、SwiftUIは@ObservedObject var model: UserViewModel?をサポートしています。ただし、オブジェクトがnilの間、ビューは変更を購読しません。値が割り当てられると、購読が自動的にアクティブになります。

@ObservedObjectと@EnvironmentObjectの違いは何ですか?

@ObservedObjectはイニシャライザを介してオブジェクトを受け取り、@EnvironmentObjectはSwiftUI環境を介して受け取ります。@EnvironmentObjectはコンストラクターを介した明示的な受け渡しを必要としませんが、オブジェクトは階層の最上位レベルで注入される必要があります。

ObservableObjectの変更を手動でSwiftUIに通知するには?

プロパティを変更する前にobjectWillChange.send()を呼び出します。これは@Publishedが適さない場合(例えば、計算プロパティや、変更前に通知する必要があるコレクション操作)に便利です。

配列内の変更で@ObservedObjectがビューを再レンダリングしないのはなぜですか?

@ObservedObjectと@Publishedは参照の置き換えを追跡し、コレクションの内容変更は追跡しません。再レンダリングをトリガーするには、配列を再代入する必要があります:items.append(newItem) → items = items、または変更前にobjectWillChange.send()を使用します。

Viewを実装していない構造体で@ObservedObjectを使用できますか?

いいえ、@ObservedObjectはViewプロトコルを実装する型内でのみ使用可能なSwiftUIのProperty Wrapperです。通常の構造体では、ObservableObjectPublisherとともにCombineを直接使用してください。

まとめ

  • @ObservedObject — 所有権なしでObservableObjectを監視するProperty Wrapper
  • @StateObject — オブジェクトを作成、@ObservedObject — 既存のオブジェクトを監視
  • @Published — ObservableObjectプロパティの自動パブリッシャー
  • 購読 — @ObservedObject使用時にSwiftUIが自動的にCombine購読を管理
  • 構成 — ビューは複数のObservableObjectを同時に監視可能
  • Main actor — @Publishedプロパティはメインスレッドでのみ変更すべき
  • EnvironmentObject — 環境を介した暗黙的な受け渡しのための@ObservedObjectの代替

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください