【SwiftUI】Property Wrapper @Observedobjectと@StateObject
iOS14で追加になった、@StateObjectについてみていきます。親Viewが状態が変化され、再描画されると状態が破棄される@ObservedObjectとは異なり、@StateObjectは状態は保持されます。下記簡単なサンプルを掲載します。
1. 例について
親VIewに乱数のテキストと乱数の更新する青いボタンがあり、子のViewにそれぞれHStackで更新ボタンと更新ボタンを押下するとカウントアップするViewを配置します。下のスクリーンショットは、子のViewに緑と赤の更新ボタンを配置しております。青いボタンのあるViewには、@ObservedObjectが定義されており、赤いViewには@StateObject定義されてます。
親Viewにある乱数の更新ボタンを押下すると親Viewが更新され、その時に、子のViewがどうなるかを見るサンプルです。
2. SampleView,SampleView2を更新
青と赤の更新ボタンを押下してそれぞれ、4までカウントアップします。
3. 親Viewを更新
乱数の更新ボタンを押下すると親Viewが更新され、乱数の表示が変わります。この時、子Viewのそれぞれは下図のように変わります。@StateObjectを定義した赤いボタンを含むViewは0にならずリセットされませんでした。
4. サンプルコード
上記の例で利用したコードです
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
@State var title = 0 | |
var body: some View { | |
VStack(spacing: 0.0) { | |
Text("乱数:\(self.title)").padding(.bottom,10.0) | |
Button("乱数の更新\n(Viewの更新)") { | |
self.title = Int.random(in: 0...50) | |
}.modifier(MyButton(color: .blue)) | |
Spacer().frame(height: 100.0) | |
SampleView1().padding(.bottom,20.0) | |
SampleView2() | |
} | |
} | |
} | |
struct SampleView1: View { | |
@ObservedObject var model = ViewModel() | |
var body: some View { | |
HStack(spacing:20.0) { | |
Text("SamepeView1 count: \(self.model.count)") | |
Button("更新") { | |
self.model.count += 1 | |
}.modifier(MyButton(color: .green)) | |
} | |
} | |
} | |
struct SampleView2: View { | |
@StateObject var model = ViewModel() | |
var body: some View { | |
HStack(spacing:20.0) { | |
Text("SamepeView2 count: \(self.model.count)") | |
Button("更新") { | |
self.model.count += 1 | |
}.modifier(MyButton(color: .red)) | |
} | |
} | |
} | |
class ViewModel: ObservableObject { | |
@Published var count = 0 | |
} | |
struct MyButton: ViewModifier { | |
let color: Color | |
func body(content: Content) -> some View { | |
content | |
.foregroundColor(.white) | |
.padding() | |
.background(color) | |
.clipShape(RoundedRectangle(cornerRadius: 10)) | |
} | |
} |