0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftUI の @StateObject の使い方と StateObject(wrappedValue: ...) の活用

Posted at

@StateObject とは?

@StateObject は SwiftUI において ObservableObject を管理するためのプロパティラッパーです。ビューのライフサイクルを通じて ObservableObject のインスタンスを保持し、データが更新されるとビューを再描画する役割を持ちます。

基本的な使い方

import SwiftUI

class CounterViewModel: ObservableObject {
    @Published var count = 0
    
    func increment() {
        count += 1
    }
}

struct CounterView: View {
    @StateObject private var viewModel = CounterViewModel()
    
    var body: some View {
        VStack {
            Text("\(viewModel.count)")
                .font(.largeTitle)
            Button("Increment") {
                viewModel.increment()
            }
        }
    }
}

この例では、@StateObject を使用して CounterViewModel のインスタンスを作成し、count の変更に応じてビューを更新しています。

self._model = StateObject(wrappedValue: ...) の活用

通常、@StateObject は次のように初期化します。

@StateObject private var viewModel = CounterViewModel()

しかし、ビューの init 内で @StateObject を初期化する必要がある場合は、以下のように self._model = StateObject(wrappedValue: ...) を使います。

なぜ self.model = ではなく self._model = なのか?

SwiftUI では @StateObjectビューのライフサイクルを通じてオブジェクトを一度だけ作成する べきものとされています。そのため、init 内で self.model = CounterViewModel(data: data) のように直接代入することはできません。

self._model = StateObject(wrappedValue: ...) を使うことで、以下のように ObservableObject を安全に初期化できます。

実際のコード例

import SwiftUI

class CounterViewModel: ObservableObject {
    @Published var count: Int
    
    init(initialCount: Int) {
        self.count = initialCount
    }
    
    func increment() {
        count += 1
    }
}

struct ContentView: View {
    @StateObject private var model: CounterViewModel

    init(initialCount: Int) {
        self._model = StateObject(wrappedValue: CounterViewModel(initialCount: initialCount))
    }

    var body: some View {
        VStack {
            Text("\(model.count)")
                .font(.largeTitle)
            Button("Increment") {
                model.increment()
            }
        }
    }
}

このパターンが必要なケース

  1. init で外部から渡されたデータを使って ObservableObject を初期化したい場合
  2. 複雑な ObservableObject の初期化ロジックが必要な場合
  3. SwiftUI の制約により、直接 self.model = ... できない場合

@ObservedObject@EnvironmentObject との違い

@ObservedObject

  • ObservableObject外部から渡して 使用する。
  • View のライフサイクルでは ObservableObject を作成しない。
struct SomeView: View {
    @ObservedObject var viewModel: CounterViewModel
}

@EnvironmentObject

  • @EnvironmentObject@ObservedObject の一種で、SwiftUI の Environment を通じてオブジェクトを受け取る。
struct SomeOtherView: View {
    @EnvironmentObject var viewModel: CounterViewModel
}

@StateObject の適用タイミング

使用する場面 適切なプロパティラッパー
ビュー内で ObservableObject のライフサイクルを管理したい @StateObject
すでに作成された ObservableObject を親ビューから渡したい @ObservedObject
Environment を通じて複数のビューで共有したい @EnvironmentObject
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?