오늘은 EnvironmentObject에 대해서 알아보겠습니다.
이전에 AppStorage에 대해서 정리했었죠. 그리고 글은 작성하지 않았지만, 데이터의 범위만 줄어든 SceneStorage라는 것도 있습니다. 그리고 이번에는 EvironmentObject입니다.
셋 다 뭔가 유사한 면이 있습니다. 데이터 엑세스 범위에 따라서 저장된 데이터를 공유한다는 차원에서 유사합니다. 다만 범위의 차이가 존재하죠.
AppStorage: 앱의 전체 범위
SceneStorage: Scene의 범위
EnvironmentObject: View의 범위 (SuperView ~ SubView 포함)
하나의 뷰가 있고, 그 하위 뷰에서 공유하는 하나의 데이터 객체를 공유하고 싶다고 문제상황을 가정해보겠습니다. 여기서 이전에 설명했던 AppStorage나 SceneStorage를 사용해도 문제는 해결은 되겠죠. 하지만 이것은 앱이 너무 상호의존적인 관계에 놓이게 됩니다. 만약 상황에 따라서 다른 객체로 넣고 싶을 수도 있겠죠. 하지만 AppStorage라면, 앱의 전역범위에서 다루기만하면 되는 데이터 뿐만아니라, 아주 국소적으로 사용되는 데이터도 가지고 있게되죠. 그렇게 되면, AppStorage를 떼고 기능구현을 할 수 없습니다. 즉, 모듈성에 악영향이 갈 수 밖에 없습니다. 그래서 View내에서만 생존하는 그런 객체가 필요합니다.
그림을 그리면 범위에 대한 생존 기간은 다음과 같을 겁니다.
그러한 맥락에서 EnvironmentObject
를 사용한다고 봅니다.
그러면 이것을 어떻게 사용하면될까요?
아주 간단합니다.
App의 EntryPoint가 다음과 같습니다.
@main
struct EnvironmentObject_ExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
그리고 ObservableObject를 하나 생성하겠습니다.
class UserInfo: ObservableObject {
@Published var name = ""
}
그리고 앱을 실행하면 처음으로 보이는 View는 다음과 같습니다.
struct ContentView: View {
var body: some View {
TabView {
FirstTabView()
.tabItem {
Image(systemName: "1.circle")
Text("첫 번째 탭")
}
SecondTabView()
.tabItem {
Image(systemName: "2.circle")
Text("두 번째 탭")
}
}
.environmentObject(UserInfo())
}
}
.environmentObject(UserInfo())
UserInfo
객체를 하위뷰에서 접근할 수 있습니다.아주 간단한 UI 입니다..^^
하위뷰에서는 다음과 같이 접근합니다.
struct FirstTabView: View {
@EnvironmentObject var userInfo: UserInfo
var body: some View {
VStack {
Text("첫 번째 탭")
.font(.system(size: 35, weight: .bold, design: .rounded))
.padding(.top, 35)
Spacer()
Text("INPUT")
TextField("값을 입력해보세요.", text: $userInfo.name)
Spacer()
}
}
}
@EnvironmentObject var userInfo: UserInfo
다른 뷰에서도 아래와 같이 접근하고 있으며 같은 데이터를 공유하고 있습니다.
struct SecondTabView: View {
@EnvironmentObject var userInfo: UserInfo
var body: some View {
VStack {
Text("두 번째 탭")
.font(.system(size: 35, weight: .bold, design: .rounded))
.padding(.top, 35)
Spacer()
Text("Output")
Text(userInfo.name)
Spacer()
}
}
}
위 상황을 도식화 하면 다음과 같습니다.
아무리 병렬적으로 가능하다고 해도 아래와 같은(보라색) 처럼 데이터 공유는 불가능합니다. (직접적인 공유는 안되고, 구조에 따라서 위로 전달 된 이후에, 하위로 다시 내려오는 식으로 전달은 되겠죠.)
이 외 사항들을 정리해보면 다음과 같습니다.
ex) 불가능한 예시
@EnvironmentObject var viewModel: CommonViewModel
init() {
if viewModel.username == "Uno" {
title = "Uno"
}
}
읽어주셔서 감사합니다.