ํ”„๋กœ์ ํŠธ ๐Ÿ› ๏ธ/iOS

@StateObject @ObserverdObject ๊ทธ๋ž˜์„œ ๋ญ์‹œ ๋‹ค๋ฅธ๋””

WonderPark 2023. 4. 6. 21:34

@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(ํ•˜์œ„๋ทฐ) ์— ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์˜ˆ์‹œ์ด๋‹ค.

  1. ์ฒ˜์Œ ContentView(์ƒ์œ„๋ทฐ)์— @StateObject ๋ฅผ ์„ ์–ธํ•ด์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ ํ›„์—

 

2. MagazineMainView(ํ•˜์œ„๋ทฐ) ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. 

 

3. ์ „๋‹ฌ๋œ ์ธ์Šคํ„ด์Šค๋ฅผ MagazineMainView(ํ•˜์œ„๋ทฐ) ์—์„œ๋Š” ObservedObject๋กœ ๋ฐ›์•„์ค€๋‹ค.

 

 

 

๊ฒฐ๋ก !! 

@Stateobject ๋Š” ์ตœ์ƒ๋‹จ๋ทฐ์—์„œ ๋”ฑ ํ•œ๋ฒˆ๋งŒ ์ƒ์„ฑ! ํ•˜์œ„๋ทฐ์—๋Š” ObservedObject ์‚ฌ์šฉ! ์œผ๋กœ ์•Œ์ž˜๋”ฑ ๋งˆ๋ฌด๋ฆฌ ํ•˜๊ฒ ๋‹ค.