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 초기화 필수!
[참조자료]
[Ellen] FAQ: CS101 (0) | 2024.08.21 |
---|---|
NavigationStack, NavigationPath and navigationDestination (0) | 2024.08.19 |
@State and @Binding (0) | 2024.08.11 |
[Swift] 좋은 데이터 구조 (feat. chatGPT) (0) | 2024.07.06 |
[Swift] ERD(Entity Relationship Diagram) (0) | 2024.07.06 |
댓글 영역