はじめに
ObservedObject
を用いたページにおいて、その上位ページの値がeventlistenerによって変化する度に現在のページが初期化されることがあった。
ViewModelからデータを共有する方法は大きくStateObject
とObvservedObject
の2つがある。
よってこの2つの使い方や特徴をまとめる。
環境
Xcode 13.3.1
構成
APP
| Mainview.swift
\ーchildrenPages
| ObservedObjectView.swift
| StateObjectView.swift
Code
MainView
class MainViewModel: ObservableObject {
@Published var mainCount = 0
}
struct MaintView: View {
@ObservedObject var viewmodel = MainViewModel()
var body: some View {
NavigationView {
VStack{
Text(viewmodel.mainCount.description)
.font(.title)
NavigationLink("ObservedObject") {
ObservedOjectView(mainCount: $viewmodel.mainCount)
}
.font(.title)
.padding()
NavigationLink("StateObject") {
StateObjectView(mainCount: $viewmodel.mainCount )
}
.font(.title)
.padding()
}
}
}
}
StateObjectView
class StateObjectViewModel: ObservableObject {
@Published var count = 0
func addCount() {
self.count += 1
}
}
struct StateObjectView: View {
@StateObject var viewmodel = StateObjectViewModel()
@Binding var mainCount : Int
var body: some View {
VStack{
Text("StateObject : \(viewmodel.count.description)")
.font(.title)
.padding()
.onTapGesture {
viewmodel.addCount()
}
Button {
self.mainCount += 1
} label: {
Text("change main view count")
.font(.title)
}
Text(self.mainCount.description)
.font(.title)
}
}
}
ObservedObjectView
class ObservedOjectViewModel : ObservableObject {
@Published var observedCount = 0
func addCount() {
self.observedCount += 1
}
}
struct ObservedOjectView: View {
@ObservedObject var viewmodel = ObservedOjectViewModel()
@Binding var mainCount : Int
var body: some View {
VStack{
Text("Observed : \(viewmodel.observedCount.description)")
.font(.title)
.padding()
.onTapGesture {
viewmodel.addCount()
}
Button {
self.mainCount += 1
} label: {
Text("change main view count")
.font(.title)
}
Text(self.mainCount.description)
.font(.title)
}
}
}
Screen
@Binding
によって上位ページの値が変化するようにした。
@ObservedObject
: 画面に入る時、初期化されない。 上位ページによって初期化される。
@StateObject
: 画面に入る時、初期化される。 上位ページによって初期化されない。
DBを用いたプロジェクトでは値が頻繁に変化するので、@StateObject
を利用することが多いと思いました。