Closed5

@ObservedObjectを知りたい我

ほへとほへと

とりあえず公式を見る。
https://developer.apple.com/documentation/swiftui/observedobject


概要

監視可能なオブジェクトをサブスクライブし、監視可能なオブジェクトが変更されるたびにビューを無効にするプロパティ ラッパー タイプ。

@MainActor @propertyWrapper @preconcurrency @frozen
struct ObservedObject<ObjectType> where ObjectType : ObservableObject

Add the @ObservedObject attribute to a parameter of a SwiftUI View when the input is an ObservableObject and you want the view to update when the object’s published properties change. You typically do this to pass a StateObject into a subview.

StateObjectをサブViewに渡すために、@ObservedObjectを使用すると記載がある。

次の例では、データ モデルを監視可能なオブジェクトとして定義し、ビューでモデルを状態オブジェクトとしてインスタンス化してから、そのインスタンスを監視対象オブジェクトとしてサブビューに渡します。

class DataModel: ObservableObject {
    @Published var name = "Some Name"
    @Published var isEnabled = false
}

struct MyView: View {
    @StateObject private var model = DataModel()

    var body: some View {
        Text(model.name)
        MySubView(model: model)
    }
}

struct MySubView: View {
    @ObservedObject var model: DataModel

    var body: some View {
        Toggle("Enabled", isOn: $model.isEnabled)
    }
}

Don’t specify a default or initial value for the observed object. Use the attribute only for a property that acts as an input for a view, as in the above example.

@ObservedObjectにデフォルト値や初期値を指定しないでとの記載がある。@ObservedObject属性は親ViewやモデルからViewに提供されるデータを使用する。これにより、Viewがデータを所有するのではなく、単に観察することになる。初期値を指定することは、Viewがオブジェクトの状態を管理することを意味し、これは@ObservedObjectの目的に反する。

ほへとほへと

@StateObjectについても調べてみる。
https://developer.apple.com/documentation/swiftui/stateobject


概要

監視可能なオブジェクトをインスタンス化するプロパティ ラッパー タイプ。

@MainActor @frozen @propertyWrapper @preconcurrency
struct StateObject<ObjectType> where ObjectType : ObservableObject

ビュー階層に格納する参照型の唯一の真実のソースとして状態オブジェクトを使用します。プロパティ宣言に @StateObject 属性を適用し、ObservableObject プロトコルに準拠する初期値を提供することで、App、Scene、または View に状態オブジェクトを作成します。状態オブジェクトをプライベートとして宣言して、メンバー単位の初期化子から設定されないようにします。メンバー単位の初期化子は、SwiftUI が提供するストレージ管理と競合する可能性があります。

→ @StateObjectで宣言されたものが基準となる。

class DataModel: ObservableObject {
    @Published var name = "Some Name"
    @Published var isEnabled = false
}

struct MyView: View {
    @StateObject private var model = DataModel() // Create the state object.

    var body: some View {
        Text(model.name) // Updates when the data model changes.
        MySubView()
            .environmentObject(model)
    }
}

ObservedObject 属性を持つプロパティを介して、状態オブジェクトをサブビューに渡すことができます。または、上記のコードの MySubView のように、environmentObject(_:) 修飾子をビューに適用して、オブジェクトをビュー階層の環境に追加します。その後、EnvironmentObject 属性を使用して、MySubView またはその子孫内のオブジェクトを読み取ることができます。

→ EnvironmentObjectを使用して、サブView側で使用することができる。

struct MySubView: View {
    @EnvironmentObject var model: DataModel


    var body: some View {
        Toggle("Enabled", isOn: $model.isEnabled)
    }
}
ほへとほへと

以下の違いについて、ChatGPTに聞いてみた。

@StateObject private var model = DataModel()
private var model = DataModel()

・@StateObjectは、Viewが生成されタイミングで生成し、Viewが破棄されたタイミングで破棄
・@StateObjectは、再描画時にリセットされない
・@StateObjectは、監視を行い、変更があった場合に再描画処理を実行する


詳細

@StateObject を使用するパターンと private var model = DataModel() を使用するパターンの違いは、SwiftUIの状態管理の方法とライフサイクルにあります。以下にそれぞれの違いを説明します。

@StateObject を使用するパターン

@StateObject private var model = DataModel()
  1. ライフサイクル管理:

    • @StateObject を使うと、SwiftUIは DataModel のインスタンスをビューのライフサイクルに合わせて管理します。ビューが作成されたときにインスタンスが作成され、ビューが破棄されたときにインスタンスも破棄されます。
    • ビューが再レンダリングされる際にも、同じインスタンスが使用されるため、状態が保持されます。
  2. 状態管理:

    • @StateObject はそのインスタンスが変更されるたびにビューを再描画します。例えば、DataModelname プロパティが変更されると、ビューの該当部分が自動的に更新されます。
  3. 使い方の場所:

    • 主にビューのルートレベルや独立したビューに対して使用されます。

private var model = DataModel() を使用するパターン

private var model = DataModel()
  1. ライフサイクル管理:

    • この場合、DataModel のインスタンスはビューの再レンダリング時に毎回新しいインスタンスが作成されます。ビューが再描画されるたびに新しい DataModel が作成されるため、状態がリセットされます。
  2. 状態管理:

    • @Published プロパティに対する変更はビューに通知されません。したがって、DataModel のプロパティが変更されてもビューは再描画されません。
  3. 使い方の場所:

    • 主にビューの一部で使い捨ての状態を保持する場合や、状態が他のビューと共有されない場合に使用されます。

結論

  • @StateObject はビューのライフサイクルに合わせて状態を保持し、状態が変更されたときにビューを再描画するために使用します。
  • private var model = DataModel() は一時的な状態を保持するために使用し、ビューが再描画されるたびに新しいインスタンスを作成します。

従って、MyView では @StateObject を使用することで、DataModel の状態が正しく管理され、プロパティの変更がビューに反映されるようになります。

このスクラップは5ヶ月前にクローズされました