@Stateobject ์ @ObservedObject ๋๋์ฒด ๋ญ๊ฐ ๋ค๋ฅด๊ณ ์ด๋ป๊ฒ ์ฌ์ฉํด์ผํ ๊น?
SwiftUI๋ก ๊ฐ๋ฐ์ ํ๋ฉด์ ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๊ณ , ๋๋ฅผ ๊ฐ์ฅ ๋ง์ด ๊ดด๋กญํ๋ ,,
๋๋์ฒด ์ด ๋์ ๋ญ๊ฐ ๋ค๋ฅธ๊ฒ์ด๋ฉฐ, ๋ ์ด๋ป๊ฒ ์! ์ฌ์ฉํด์ผํ ๊น ? ์์๋ฑ ์ ๋ฆฌํด๋ณด๊ฒ ๋ค..!! ๐ค
๋จผ์ Apple ์ ๊ณต์๋ฌธ์๋ฅผ ์ดํด๋ณด๋ฉด,

@ObservedObject ๋
observable object ๋ฅผ subscribe(๊ตฌ๋ )ํ๋ Property wrapper ์ด๊ณ , observable object ๊ฐ ๋ณํํ๋ฉด ๋ทฐ๋ฅผ ๋ฌดํจํ ์ํจ๋ค๊ณ ํ๋ค.
⇒ ์ฆ, ๋ทฐ์์ observable object๋ฅผ ๊ตฌ๋ ํ๊ณ ์ง์ผ๋ณด๋ฉด์ ์ด ๊ฐ์ฒด์ ๋ณ๊ฒฝ์ด ๊ฐ์ง๋๋ฉด ๋ทฐ๋ฅผ ๋ค์ ๊ทธ๋ ค์ ์๋ก ์ ๋ฐ์ดํธํ๋ค.

@Stateobject ๋?
observable object ๋ฅผ ์ธ์คํด์คํ ํ Property wrapper ๋ผ๊ณ ํ๋ค.
์ @ObservedObject ์๋ ์ด๋ค ์ฐจ์ด์ผ์ง, ์ข๋ ์ฝ์ด๋ณด๋ฉด
SwiftUI creates a new instance of the model object only once during the lifetime of the container that declares the state object. For example, SwiftUI doesn’t create a new instance if a view’s inputs change, but does create a new instance if the identity of a view changes.
⇒ observable object๋ฅผ ๊ตฌ๋ ํ๋ ์ธ์คํด์ค๋ฅผ “๋ฑ ํ๋ฒ” ๋ง ๋ง๋ค๊ณ
⇒ ๋ทฐ์ ์ํ๊ฐ ๋ณํด๋, ๋ฑ ํ ๋ฒ ๋ง๋ค์ด์ง ์ธ์คํด์ค๋ @StateObject์ ์๋ช ์ฃผ๊ธฐ๋์ ๋ค์ ๋ง๋ค์ด์ง์ง ์๋๋ค.
⇒ observable object์ ์๋ @published ํ๋กํผํฐ์ ์ํ ๋ณํ๊ฐ ์๊ธฐ๋ฉด, ๋ทฐ๋ฅผ ์๋ก ๋ค์ ๊ทธ๋ฆฌ๋๊ฒ์ด ์๋๋ผ ํด๋น ํ๋กํผํฐ๊ฐ ์ฌ์ฉ๋๋ ๋ถ๋ถ๋ง ์ ๋ฐ์ดํธํ๋ค.
๋ฐฑ๋ฌธ์ด ๋ถ์ฌ์ผํ! ์ฐจ์ด๋ค์ ์ค์ ์ฝ๋์ ์ ์ฉ์์ผ์ ์ดํดํด๋ณด์.
๋จผ์ CounterStore๋ผ๋ observable object ๋ฅผ ํ๋ ๋ง๋ค์ด์ค๋ค.
final class CounterStore: ObservableObject {
@Published var count = 0
func reset() {
count = 0
}
func plusOne() {
count += 1
}
}
StateCounterView , ObservedCounterView ๋ผ๋ ๊ฐ๊ฐ์ ํ์๋ทฐ(SubView)๋ค์ ๋ง๋ค์ด ๋ฃ์ด์ค๋ค.
์ฌ๊ธฐ์ StateCounterView๋ StateObject ๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , ObservedCounterView ๋ ObservedObject๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
struct StateCounterView: View {
@StateObject var counterStore: CounterStore = CounterStore()
var body: some View {
VStack {
Text("\(counterStore.count)")
.font(.largeTitle)
HStack {
Spacer()
Button {
counterStore.reset()
} label: {
Text("reset")
.font(.largeTitle)
}
Spacer()
Button {
counterStore.plusOne()
} label: {
Text("plus 1")
.font(.largeTitle)
}
Spacer()
}
}
}
}
struct ObservedCounterView: View {
@ObservedObject var counterStore: CounterStore = CounterStore()
var body: some View {
VStack {
Text("\(counterStore.count)")
.font(.largeTitle)
HStack {
Spacer()
Button {
counterStore.reset()
} label: {
Text("reset")
.font(.largeTitle)
}
Spacer()
Button {
counterStore.plusOne()
} label: {
Text("plus 1")
.font(.largeTitle)
}
Spacer()
}
}
}
}
์์๋ทฐ(SuperView) ๋ฅผ ๋ง๋ค๊ณ , @State ๋ณ์ isClicked ๋ฅผ ํ๋ ์ ์ธํ์ฌ ์ด ๋ณ์์ ์ํ๊ฐ ๋ณ๊ฒฝํ๋ฉด์ ๋ทฐ๋ฅผ ์๋ก ๊ทธ๋ฆฌ๋๋ก ํด๋ณด์.
์ด๋ฅผ ํตํด ์๊ณ ์ถ์๊ฒ์ ์์๋ทฐ์์ ๋ทฐ๊ฐ ์๋ก ๊ทธ๋ ค์ง๋, ์ด ๋๊ฐ์ ํ์๋ทฐ๋ ์ด๋ค ์ฐจ์ด์ ์ ๋ณด์ผ์ง์ด๋ค.
struct ContentView: View {
@State private var isClicked: Bool = false
var body: some View {
VStack {
Group {
Button {
isClicked.toggle()
} label: {
Text(isClicked ? "ON" : "OFF")
.font(.title)
.background(.yellow)
}
}
Spacer()
Group {
Text("subview StateObject")
.bold()
StateCounterView()
}
Spacer()
Group {
Text("subview ObservedObject")
.bold()
ObservedCounterView()
}
Spacer()
}
.padding()
}
}
๊ฒฐ๊ณผ

ON/OFF ๋ฒํผ์ ๋๋ฅด๋ฉด isClicked๋ผ๋ @State ๋ณ์์ ์ํ๊ฐ Update ๋๋ค.
๊ทธ๋ฌ๋ฉด ์ด์ ๊ฐ์ด StateCounterView(ํ์๋ทฐ)๋ ์์๋ทฐ๊ฐ ๋ค์ ๊ทธ๋ ค์ง๋ ๊ฒ๊ณผ๋ ๋ณ๊ฐ๋ก ๋ทฐ๊ฐ ๋ค์ ๊ทธ๋ ค์ง์ง ์๊ณ , ํ์๋ทฐ์์ ๊ณ์ ์ด์๋จ์์ ํ์ฉ๋๋ค.
๋ฐ๋ผ์ StateCounterView์ CounterStore()์ ์ด๊ธฐํ๋ ๋ฑ ํ๋ฒ๋ง ์คํ๋๋ค.
๋ฐ๋ฉด , ObservedCounterView(ํ์๋ทฐ)๋ ObservedObject๋ ์์๋ทฐ์ ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด ๋ค์ ๊ทธ๋ ค์ ธ์ผ ํ ๋๋ง๋ค, subView์์์ ๋ค์ ๋ง๋ค์ด์ง๋ค.
์ฆ , ObservedCounterView์ CounterStore() ์ด๊ธฐํ๋ ์์๋ทฐ๊ฐ ๋ค์ ๊ทธ๋ ค์ง๋๋ง๋ค ์คํ๋๋๊ฒ์ด๋ค.
์ด๋ฅผ ๋ณด๊ณ ๋๋ ์ฐจ์ด์ ์ StateObject๋ ๋ทฐ์๋ ๋ณ๊ฐ๋ก ์กด์ฌํ๋ ์ธ์คํด์ค ๊ฐ์ ๋๋์ด๊ณ ,
ObservedObject ๋ ๋ทฐ์ ๋์์ ์กด์ฌํ๋ ๋๋?
ObservedObject๋ ๋ทฐ์ ์ข ์๋ ๋๋์ด๊ณ , StateObject๋ ๋ทฐ์ ๋ ๋ฆฝ๋ ๋๋์ด๋ค.
๋ SwiftUI๋ก ์ฑ์ ๋ง๋ค๋ค ๋ณด๋ฉด StateObject์ ObservedObject ๋ฅผ ํ์์ ์ผ๋ก ๋ง์ด ์ฌ์ฉํ๊ฒ ๋๋๋ฐ,
๊ฐ๋ฐ์ ํ๋ฉด์ StateObject ์ ObservedObject ๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๋ค๋ณด๋,
์ด ๋๊ฐ์ง๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํด์ผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ผ๊น ๋ผ๋ ๊ณ ๋ฏผ์ ํ๊ฒ ๋์๋ค. ๐ค
ํนํ ์์๋ทฐ์์ @StateObject๋ฅผ ์ ์ธํด์ instance๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ ,
ํ์๋ทฐ์์ ์ด ์ธ์คํด์ค๋ฅผ ์ ๋ฌ๋ฐ์์ ์ฌ์ฉํ ๋ @StateObject๋ก ๋ฐ์์ฃผ๋ค๊ฐ, ์ฑ์ด ํฐ์ ธ๋ฒ๋ฆฌ๋ ๊ฒฝ์ฐ๋ ์์๋ค. ๐คฏ
์๊ฐํด๋ณด๋ฉด @StateObject ๋ ์์์ ์์๋ณธ ๋ด์ฉ ์ฒ๋ผ ObservableObject ์ ์ธ์คํด์ค ๋ฑ ํ๋ฒ ์์ฑ์ ํ๋ค.
๊ทธ๋์ ์์๋ทฐ์ StateObject๋ฅผ ์ ์ธํ์๋, ํ์๋ทฐ์์๋ @StateObject ๋ก ๋ฐ์์ฃผ๊ฒ ๋๋ฉด ์ด ์ธ์คํด์ค๊ฐ ํ์๋ทฐ์์๋ ๊ฐ์ด ๊ด๋ฆฌ๊ฐ ๋๊ธฐ ๋๋ฌธ์ ์ํํ ์ ์๋ค.
๋ฐ๋ผ์ ๊ฐ๋ฐ์ ํ ๋!
์์๋ทฐ์ ํ์๋ทฐ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์ ๋ฌ์ ํ๋ ์ํฉ์์๋,
@StateObject ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ต์๋จ๋ทฐ์์ ํ๋ฒ ์ธ์คํด์ค๋ฅผ ์ด๊ธฐํ ์์ผ์ฃผ๊ณ , ๊ทธ ์ธ์คํด์ค๋ฅผ ๋๊ฒจ๋ฐ๋ ํ์๋ทฐ๋ค์์๋ @ObservedObject๋ก ๋๊ฒจ๋ฐ์์ ๋ง๋ค์ด์ง @StateObject ์ธ์คํด์ค๋ฅผ ๋จ์ง ๊ด์ฐฐํ๋ ์ญํ ๋ง์ผ๋ก ์ฌ์ฉํด์ฃผ๋๊ฒ์ด ์ข์ ๋ฏ ํ๋ค!
์ถ์ฒ !!!
์ด๊ฒ์ ContentView(์ต์๋จ๋ทฐ) → MagazineMainView(ํ์๋ทฐ) ์ ์ธ์คํด์ค๋ฅผ ์ ๋ฌํ๋ ์์์ด๋ค.
- ์ฒ์ ContentView(์์๋ทฐ)์ @StateObject ๋ฅผ ์ ์ธํด์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ํ์

2. MagazineMainView(ํ์๋ทฐ) ์ ๋ค์๊ณผ ๊ฐ์ด ์ธ์คํด์ค๋ฅผ ์ ๋ฌํ๋ค.

3. ์ ๋ฌ๋ ์ธ์คํด์ค๋ฅผ MagazineMainView(ํ์๋ทฐ) ์์๋ ObservedObject๋ก ๋ฐ์์ค๋ค.

๊ฒฐ๋ก !!
@Stateobject ๋ ์ต์๋จ๋ทฐ์์ ๋ฑ ํ๋ฒ๋ง ์์ฑ! ํ์๋ทฐ์๋ ObservedObject ์ฌ์ฉ! ์ผ๋ก ์์๋ฑ ๋ง๋ฌด๋ฆฌ ํ๊ฒ ๋ค.
'ํ๋ก์ ํธ ๐ ๏ธ > iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| URLSession + Combine ์กฐํฉ์ผ๋ก ๋คํธ์ํฌ ๋ ์ด์ด ๋ง๋ค๊ธฐ (0) | 2023.06.10 |
|---|---|
| Combine(3): Operator (0) | 2023.06.10 |
| Combine(2): Subject (0) | 2023.06.10 |
| Combine(1): Publisher, Subscriber! (0) | 2023.06.10 |
| Firebase Storage ์ asnyc/await ๋ฅผ ์ฌ์ฉํด์ ๋ค์ค์ด๋ฏธ์ง ์ฒ๋ฆฌํ๊ธฐ (0) | 2023.04.06 |