iOS 응용 (SwiftUI)

[iOS -SwiftUI] @StateObject, @ObservedObject, @EnvironmentObject 때에 맞게 사용하기 (데이터 넘기기, 부모 뷰 -> 자식 뷰)

jake-kim 2024. 9. 23. 01:53

@StateObject, @EnvionrmentObject, @ObservedObject 구분

  • 모두 ObservableObject 타입의 모델을 프로퍼티로 선언할 때 사용
class MyObject: ObservableObject {
    @Published var age = 0
}

struct ContentView: View {
    @StateObject var object1 = MyObject()
    @ObservedObject var object2 = MyObject()
    @EnvironmentObject var object3: MyObject
    
    var body: some View {
    }
}

 

  • 차이점?
    • @StateObject: 이 프로퍼티는 오직 이것을 선언한 뷰 라이프 사이클에서만 관리
    • @ObservedObject: 이 프로퍼티는 이것을 선언한 뷰 라이프 사이클 뿐만이 아닌 다른 곳에서도 변경이 가능
    • @EnvironmentObject: 부모 -> 자식 관계가 명확하고 특성은 @ObservedObject와 동일

부모 뷰 -> 자식 뷰 상황에서 때에 맞게 사용하는 방법

  • 가정) 부모 뷰에서 데이터를 가지고 자식 뷰에 데이터를 넘기는 상황
  • 1) 부모 뷰에서 변경이 있고, 자식 뷰에서도 변경이 있는 경우?
    • 부모 뷰의 데이터는 @ObservedObejct로 선언하고 자식 뷰는 @EnvironmentObject로 선언
    • (단, 자식뷰에서 @EnvironmentObject가 아닌 @ObservedObject로 선언해도 무방)
// 부모 뷰
@main
struct ExStateObjectApp: App {
    var contentView = ContentView()
    @ObservedObject var object = MyObject()
    
    var body: some Scene {
        WindowGroup {
            contentView
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                        object.age += 1
                        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                            object.age += 1
                        }
                    }
                }
        }
        .environmentObject(object)
    }
}

// 자식 뷰
struct ContentView: View {
    @EnvironmentObject var object1: MyObject
    
    var body: some View {
        VStack {
            Text("age: \(object1.age)")
            Text("name: \(object1.name)")
        }
        .padding()
        
    }
}
  • 2) 부모 뷰에서는 변경이 없고, 자식 뷰에서만 변경이 있는 경우?
    • 부모 뷰는 @StateObject로 선언하고 자식 뷰는 @ObservedObject로 선언
// 부모 뷰
@main
struct ExStateObjectApp: App {
    var contentView = ContentView()
    @StateObject var object = MyObject()
    
    var body: some Scene {
        WindowGroup {
            contentView
        }
    }
}

// 자식 뷰
struct ContentView: View {
    @EnvironmentObject var object1: MyObject
    
    var body: some View {
        VStack {
            Text("age: \(object1.age)")
            Text("name: \(object1.name)")
        }
        .padding()
        
    }
}

* 읽어보면 좋은 글

- @StateObject vs @ObservedObject (#ViewModel, 뷰 상태관리)

- @StateObject 사용 주의사항 (Accessing StateObject's object without being installed on a View. This will create a new instance each time.)