상세 컨텐츠

본문 제목

ObservableObject, @ObservedObeject, @StateObject, @EnvironmentObject

Swift&SwiftUI

by (방울)도마토 2024. 8. 12. 14:11

본문

SwiftUI의 View를 생성할 때 고려해야 할 점

1. What data does this view need?

2. How will it use that data?

3. Where does the data come from?

 

# State

- State는 해당 뷰에만 사용할 수 있음 

→ 하위 뷰가 아니거나 Binding이 구현되지 않은 다른 뷰는 접근할 수 없음

- 일시적인 것이여서 상위 뷰가 사라지면 그 상태도 사라짐 

 

→ ObservableObject는 여러 다른 뷰들이 외부에서 접근할 수 있는 지속적인 데이터를 표현하기 위해 사용!

1. ObservableObject

A type of object with a publisher that emits before the object has changed.

- 데이터를 변경할 수 있는 객체로, 데이터가 변경될 때 해당 데이터를 사용하는 뷰에게 알릴 수 있는 object

- ObservableObject의 데이터를 사용하는 뷰는 데이터가 변경될 때마다 새롭게 업데이트 됨 

- 클래스 내부의 @Published를 통해 데이터가 변경될 때마다 변경 사실을 모든 뷰에게 알림 

class NewsProducer: ObservableObject {
    // @Published 를 통해 해당 latestNews가 변경될 때마다 이 사실을 모든 뷰에게 알림
    @Published var latestNews: String = "Breaking News!"
}

 

 

2. @ObservedObeject

A property wrapper type that subscribes to an observable object and invalidates a view whenever the observable object changes.

- ObservableObject를 관찰하고 있음을 의미 

- 뷰를 관찰하는 객체로, 데이터를 직접 소유하지 않지만 변경 사항을 반영 → 변경될 때마다 업데이트 

 

* 'invalidate'?

- 해당 뷰가 최신 상태가 아니게 되었음을 SwiftUI 시스템에 알리는 것을 의미 

- 데이터가 변경되었기 때문에 뷰의 내용이 현재 데이터 상태를 정확하게 반영하지 않는다고 판단되면, SwiftUI는 뷰를 다시 렌더링할 필요가 있다고 판단 → 뷰는 새로운 데이터로 업데이트되어 사용자에게 보여지게 됨 

- 뷰의 내용이 항상 최신의 데이터를 반영하도록 보장, 사용자의 인터페이스가 일관성있고 정확하게 유지되도록 도움 

 struct NewsView: View {
    // NewsView는 NewsProducer를 관찰, NewsProducer가 변경될 때마다 뷰가 새롭게 업데이트됨
    // 하지만 이 데이터 자체를 소유하지는 않음
    @ObservedObject var newsProducer = NewsProducer()

    var body: some View {
        Text(newsProducer.latestNews)
    }
}

 

 

3. @StateObject

- 뷰가 소유하고 관리하는 object

- 뷰가 처음 생성될 때 객체를 생성하며, 뷰가 사라질 때 객체도 사라짐 → 뷰의 라이프 사이클에 따라 객체를 존재 

 

* @ObservedObeject와의 주요 차이점

- @ObservedObeject로 선언된 객체는 다른 곳에서 생성되고 관리됨 → 사용되는 동안 SwiftUI 시스템에 의해 파괴되거나 다시 생성될 위험이 있음(뷰가 사라지거나 다시 나타날 때 객체의 상태가 유지되지 않을 수 있음)

- @StateObject를 사용하면, 그 객체는 뷰에 의해 직접 생성되고 소유 → 해당 뷰가 화면에 표시되는 동안 객체가 안전하게 유지, 뷰나 그 하위 뷰들이 필요로 하는 한 계속 객체를 사용할 수 있음 

struct MainView: View {
    // MainView는 @StateObject로 NewsProducer를 소유, NewsView에 전달 
    // MainView가 사라질 때까지 newsProducer가 유지됨
    @StateObject var newsProducer = NewsProducer()

    var body: some View {
        NewsView(newsProducer: newsProducer)
    }
}

 

 

4. @EnvironmentObject

A property wrapper type for an observable object that a parent or ancestor view supplies.

- Both a view modifier and a property wrapper

- 앱 전체에서 공유될 수 있는 객체 → 여러 뷰에서 접근할 수 있음 

- 최상위 뷰에서 EnvironmentObject를 주입하고 하위 뷰들은 @EnvironmentObject를 통해 데이터에 접근 가능 

@main
struct MyApp: App {
    // @StateObject를 통해 newsProducer를 생성
    @StateObject var newsProducer = NewsProducer()

    var body: some Scene {
        WindowGroup {
        // 최상위 뷰에서 View modifier로 지정하여 모든 뷰에서 사용할 수 있도록 함
            ContentView().environmentObject(newsProducer)
        }
    }
}

struct ContentView: View {
    // 하위 뷰에서 @EnvironmentObject를 통해 동일한 newsProducer에 접근 가능 
    @EnvironmentObject var newsProducer: NewsProducer

    var body: some View {
        Text(newsProducer.latestNews)
    }
}

 

 

 

[요약] 사용자 인터페이스와 앱의 로직에 데이터를 바인딩하는 방법

1. @State : 사용자 인터페이스 레이아웃 내의 뷰 상태를 저장하는 데 사용, 임시적이어서 해당 뷰가 사라지면 값도 없어짐 

2. ObservableObject: 사용자 인터페이스 밖에 있으며 앱 내의 SwiftUI 뷰 구조체의 하위 뷰에만 필요한 데이터 

- 데이터를 표시하는 클래스나 구조체는 ObservableObject 프로토콜을 따라야 함 

- 뷰와 바인딩될 프로퍼티는 @Published 프로퍼티 래퍼를 사용하여 선언 

- 뷰 선언부에 ObservableObject와 바인딩 하려면 @ObservedObject, @StateObject 를 사용(@StateObject가 선호되는 옵션)

3. @EnvironmentObject: 사용자 인터페이스 밖에 있으며 여러 뷰가 접근해야 하는 데이터일 경우 

- @EnvironmentObject 프로퍼티 래퍼를 사용하여 SwiftUI 뷰 파일 내 선언 

- 하위 뷰 접근 전 .environmentObject() 를 사용하여 뷰 계층 구조 삽입 전 EnvironmentObject 초기화 필수!


[참조자료]

 

Data Essentials in SwiftUI - WWDC20 - Videos - Apple Developer

Data is a complex part of any app, but SwiftUI makes it easy to ensure a smooth, data-driven experience from prototyping to production...

developer.apple.com

 

관련글 더보기

댓글 영역