- Total
꿈꾸는리버리
SwiftUI : StateObject 실험실 본문
저번에 stateObject랑 observedObject를 공부하고 나서 실제로 코딩을 하면서 궁금한 점이 생겨났다..!
그래서 열게된,, 실험실 !!
재밌었고,, 흥미로웠다 ~ ^^ !!!!
나와 같은 고민을 했던, 고민을 할 사람들에게 조금이나마 도움이 되길 바라며 ,,,
피드백과 질문 그리고 문제제기는 언제나 두 팔 벌려 환영이다 ! 🥹✨☺️
1) StateObject의 Viewmodel이 사라지는 시점
2) 그리고 이 부분은 그냥 아 그렇구나 ~ 하면서 넘겼는데 의문이 들어서 실험하게 되었다.
("애플은 Observable Object를 처음 초기화 할 때는 StateObject를 사용해서 View와 별개의 메모리 공간에 데이터를 저장하도록 하고, 이 객체화된 데이터를 넘겨 받을 때에는 @ObservedObject이나 @EnvironmentObject을 이용해서 게층 전달을 하도록 추천한다." )
1) StateObject의 Viewmodel이 사라지는 시점
다음과 같은 이유로 StateObject가 나왔다고 이전 포스팅에서 알아봤었다.
검정뷰 안에 두 개의 주황 뷰가 있다.
검정뷰의 button을 누르면 State가 변경된다.
그리고 두 주황 뷰는 각각 observedObect와 StateObject로 값을 받아 사용한다.
이렇게.. observedObect의 viewmodel은 상위 뷰의 State에 의해 body가 redrawn될 때 초기화가 된다.
StateObject는 객체화 시켜 따로 관리를 하기 때문에 상위 뷰가 redrawn이 되더라도 초기화가 되지 않는다는 것을 알아냈는데,,
이 궁금증이 해결되고 얼마 지나지 않아
그러면 .. StateObject는 언제 초기화되는 거지? 라는 의문을 가지게 되었다.
이때까지만 해도 redrawn 된다는 게 view가 사라졌다가 다시 그려진다는 건데...
흠,,, 그러면 StateObject는 view가 사라져도.. 안 없어지나..? 이런.. 고민을.. 했다...
그리고 가장 유력한 가설로, 상위 View가 사라질때 같이 사라질거다! 라고 생각을 했다.
왜냐면 상위뷰의 State가 변할때 StateObject를 유지시키더라도 상위뷰가 사라지면 StateObject를 유지할 이유가 없을 거라 예상했기 때문이다..!
와하하핫 가설이 맞았다 ~
실험을 하고 나니까 좀 당연한 결과였다고 생각이 들지만,,,, 뭐 어떤가 ~~ 재밌었으니 되었다 ^^...
그리고 당연한 말이지만, 상위뷰가 아니더라도 해당 뷰가 사라지면 viewmodel도 없어진다.
2) 그리고 이 부분을 그냥 그렇구나 ~ 하고 넘겼는데 의문이 들어서 실험하게 되었다.
검정 제일 큰 상위 뷰 하단에 주황 뷰랑 초록 뷰가 있고
초록 뷰 안에 노랑 뷰가 있다. ( 화면만 보고도 이해할 수 있도록 바깥에 테두리를 쳐놨다..! 헤헷)
검정 뷰에는 State가 있고, 버튼을 누르면 State 값이 변경된다.
struct ExperimentalView: View {
@State var test1 : Bool = false
var body: some View {
VStack{
Text(test1 ? "Test 1-1" : "Test 1")
.font(.largeTitle)
.padding()
Text("Button을 누르면 최상위 뷰의 State가 변함")
Button("Button") {
self.test1.toggle()
}
.padding()
ExtractedView2(AviewModel: TestViewModel(test2: 0))
ExtractedView3(BviewModel: TestViewModel(test2: 0))
}
.padding()
.background(
Rectangle()
.stroke(Color.black)
)
}
}
주황뷰에는 검정뷰에서 ObservedObject로 받은 A viewModel이 있고, add One 버튼을 누르면 A viewModel의 프로퍼티 값이 바뀐다.
struct ExtractedView2: View {
@ObservedObject var AviewModel : TestViewModel
var body: some View {
VStack{
Text("ObservedObject로 AviewModel을 받음")
HStack{
Text("\(AviewModel.test2)")
Button("add one") {
AviewModel.addOne()
}
}
.padding()
.background(Color.orange)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.padding()
.background(
Rectangle()
.stroke(Color.orange)
)
}
}
초록뷰에는 검정뷰에서 StateObject로 받은 B viewModel이 있고 B viewModel의 프로퍼티 값을 보여준다.
노랑뷰에서는 초록뷰에서 ObservedObject로 받은 C viewModel이 있고, add One 버튼을 누르면 C viewModel의 프로퍼티 값이 바뀐다.
✨ 이렇게 하면 초록 뷰는 위 애플 님께서 설명하신 대로 Observable Object를 처음 초기화 할 때는 StateObject를 사용해서 View와 별개의 메모리 공간에 데이터를 저장하도록 하고, 이 객체화된 데이터를 넘겨 받을 때에는 @ObservedObject을 사용하게 된다 ... ! ( 두근 )
struct ExtractedView3: View {
@StateObject var BviewModel : TestViewModel
var body: some View {
VStack{
Text("StateObject로 BviewModel을 받음")
Text("\(BviewModel.test2)")
.padding()
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(10)
HStack{
ExtractedView4(CviewModel: BviewModel)
}
}
.padding()
.background(
Rectangle()
.stroke(Color.green)
)
}
}
struct ExtractedView4: View {
@ObservedObject var CviewModel : TestViewModel
var body: some View {
VStack{
Text("ObservedObject로 CviewModel을 받음")
HStack{
Text("\(CviewModel.test2)")
Button("add one") {
CviewModel.addOne()
}
}
.padding()
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(10)
}
.padding()
.background(
Rectangle()
.stroke(Color.yellow)
)
}
}
짜란 ~ 이러면 (다행히도) 예상했던대로 초록뷰에서는 검정 뷰의 Button을 눌러
State가 변경되어도 viewmodel의 값이 유지되는 것을 확인할 수 있다!
NOTE
포스팅을 하면서는 내가 좀 삽질을 한 게 아닌가...? 하는 마음이 없지 않아 있었는데
생각해보면 오늘 포스팅한 내용이 되게 답답했었던 부분이고, 주위 사람들에게 물어봐도 쉽게 답을 얻을 수 없었던 부분들이었다.
이렇게... 한발짝씩 성장해 가는 거겠지 ...? ^!^
진짜.. 아는 만큼 보인다.. 보이는 게 힘이다..!
어제까지 나를 괴롭혔던 것들이 오늘은 좀 작아 보이는... 이런게.. 힘 !
이게 바로 ! 성장의 매력 아니겠는가 !!
헤헤 그리고 이제 진짜 정말루,, 제발,, property wrapper들과 좀 친해진 느낌..? ^^
앞으로도 화이팅이다 !
Test 1 전체 코드
//
// ExperimentalView.swift
// studing_swiftUI
//
// Created by 이가은 on 2022/06/02.
//
import SwiftUI
class TestViewModel1 : ObservableObject{
@Published var test1 : Int
init(test1 : Int) {
self.test1 = test1
print("ObservedObject init")
}
}
class TestViewModel2 : ObservableObject{
@Published var test2 : Int
init(test2 : Int) {
self.test2 = test2
print("StateObject init")
}
}
struct ExperimentalView: View {
@State var test1 : Bool = false
var body: some View {
VStack{
Text(test1 ? "test1" : "test2")
Button("Button") {
self.test1.toggle()
}
.padding()
ExtractedView1(AviewModel: TestViewModel1(test1: 0))
ExtractedView2(AviewModel: TestViewModel2(test2: 0))
}
.padding()
.background(
Rectangle()
.stroke(Color.black)
)
}
}
struct ExtractedView1: View {
@ObservedObject var AviewModel : TestViewModel1
var body: some View {
VStack{
Text("ObservedObject")
Text("\(AviewModel.test1)")
Button("add one") {
AviewModel.test1 += 1
}
}
.padding()
.background(
Rectangle()
.stroke(Color.orange)
)
}
}
struct ExtractedView2: View {
@StateObject var AviewModel : TestViewModel2
var body: some View {
VStack{
Text("StateObject")
Text("\(AviewModel.test2)")
Button("add one") {
AviewModel.test2 += 1
}
}
.padding()
.background(
Rectangle()
.stroke(Color.orange)
)
}
}
struct ExperimentalView_Previews: PreviewProvider {
static var previews: some View {
ExperimentalView()
}
}
Test 2 전체 코드
//
// ExperimentalView.swift
// studing_swiftUI
//
// Created by 이가은 on 2022/06/02.
//
import SwiftUI
class TestViewModel1 : ObservableObject{
@Published var test1 : Int
init(test1 : Int) {
self.test1 = test1
print("StateObject init")
}
}
struct ExperimentalView: View {
@State var test1 : Bool = false
var body: some View {
VStack{
Text(test1 ? "test1" : "test2")
Button("Button") {
self.test1.toggle()
}
.padding()
if(test1){
VStack{
Text("상위뷰")
.font(.largeTitle)
ExtractedView1(AviewModel: TestViewModel1(test1: 0))
}
.padding()
.background(
Rectangle()
.stroke(Color.red)
)
}
}
.padding()
.background(
Rectangle()
.stroke(Color.black)
)
}
}
struct ExtractedView1: View {
@StateObject var AviewModel : TestViewModel1
var body: some View {
VStack{
Text("StateObject")
Text("\(AviewModel.test1)")
Button("add one") {
AviewModel.test1 += 1
}
}
.padding()
.background(
Rectangle()
.stroke(Color.orange)
)
}
}
struct ExperimentalView_Previews: PreviewProvider {
static var previews: some View {
ExperimentalView()
}
}
Test 3 전체 코드
//
// ExperimentalView.swift
// studing_swiftUI
//
// Created by 이가은 on 2022/06/02.
//
import SwiftUI
class TestViewModel : ObservableObject{
@Published var test2 : Int
init(test2 : Int) {
self.test2 = test2
print("TestViewModel init")
}
func addOne(){
self.test2 += 1
}
}
struct ExperimentalView: View {
@State var test1 : Bool = false
var body: some View {
VStack{
Text(test1 ? "Test 1-1" : "Test 1")
.font(.largeTitle)
.padding()
Text("Button을 누르면 최상위 뷰의 State가 변함")
Button("Button") {
self.test1.toggle()
}
.padding()
ExtractedView2(AviewModel: TestViewModel(test2: 0))
ExtractedView3(BviewModel: TestViewModel(test2: 0))
}
.padding()
.background(
Rectangle()
.stroke(Color.black)
)
}
}
struct ExtractedView: View {
init(){
print("hi")
}
var body: some View {
HStack{
Text("hi")
}
}
}
struct ExtractedView2: View {
@ObservedObject var AviewModel : TestViewModel
var body: some View {
VStack{
Text("ObservedObject로 AviewModel을 받음")
HStack{
Text("\(AviewModel.test2)")
Button("add one") {
AviewModel.addOne()
}
}
.padding()
.background(Color.orange)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.padding()
.background(
Rectangle()
.stroke(Color.orange)
)
}
}
struct ExtractedView3: View {
@StateObject var BviewModel : TestViewModel
var body: some View {
VStack{
Text("StateObject로 BviewModel을 받음")
Text("\(BviewModel.test2)")
.padding()
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(10)
HStack{
ExtractedView4(CviewModel: BviewModel)
}
}
.padding()
.background(
Rectangle()
.stroke(Color.green)
)
}
}
struct ExtractedView4: View {
@ObservedObject var CviewModel : TestViewModel
var body: some View {
VStack{
Text("ObservedObject로 CviewModel을 받음")
HStack{
Text("\(CviewModel.test2)")
Button("add one") {
CviewModel.addOne()
}
}
.padding()
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(10)
}
.padding()
.background(
Rectangle()
.stroke(Color.yellow)
)
}
}
struct ExperimentalView_Previews: PreviewProvider {
static var previews: some View {
ExperimentalView()
}
}
'오뚝이 개발자 > SwiftUI' 카테고리의 다른 글
SwiftUI Widget 딱대.. (1/3) 위젯 기본 개념 + 구현 (0) | 2022.08.06 |
---|---|
SwiftUI launchScreen(splash Image) 만들기 ( delay가 가능한.. ) (0) | 2022.08.04 |
SwiftUI : ViewModifier (0) | 2022.06.01 |
SwiftUI : ExtractsubView (0) | 2022.06.01 |
SwiftUI : HStack, VStack, ZStack (0) | 2022.05.31 |