Swift UI - Environment 객체
Swift UI - Observable 객체
Swift UI 상태 프로퍼티 - @State Swift UI 에서 뷰의 업데이트는 뷰와 결합된 데이터를 업데이트 할 때 일어난다. 이를 위해선 데이터와 뷰 사이에 게시자 - 구독자 관계를 구축하여 할 수 있다. 이를
forstudy.tistory.com
Observable 객체는 특정 상태가 앱 내의 몇몇 뷰에 의해 사용되어야 할 경우에 적절하게 사용할 수 있다. 그러나 어떤 뷰에서 다른 뷰로 이동할 때 이동할 뷰에서도 동일한 Observable 객체에 접근해야 한다면, 대상 뷰로 Observable 객체에 대한 참조체를 전달해야 한다. 다음 코드 예제를 살펴보자
struct DemoDataView : View {
@ObservedObject var demoData : DemoData = DemoData()
var body : some View {
VStack{
...
NavigationLink(destination : SecondView(demoData)) {
Text("다음 화면으로")
}
}
}
}
위 코드에서 SecondView 로 이동할 때 SecondView 에서도 동일한 Observable 객체에 접근하기 위해 참조체를 전달하는 것을 볼 수 있다. 이 방법은 연결된 뷰나 하위 뷰로 객체를 전달할 때는 간단히 사용할 수 있겠지만, 연결되지 않거나 엄청나게 많은 뷰에서 해당 객체에 접근해야 하는 경우 코드가 매우 복잡해질 가능성이 다분하다. 이런 상황에서는 Observable object 보단 Environment object 를 사용하는 것이 더욱 바람직하다.
Environment 객체의 사용방법
Environment 객체는 Observable 객체와 같이 ObservableObject 프로토콜을 따라야 하며, 적절한 프로퍼티를 선언해야 한다. 그렇다면 일반적인 Observable 객체와의 차이점은 무엇일까? 바로 해당 객체를 참조하는 방법과, Environment 객체는 Swift UI 환경에 저장되어, 마치 전역변수마냥 모든 뷰가 접근할 수 있다는 점이다.
Environment 객체를 참조하려면 @ObservedObject 래퍼 대신에 @EnvironmentObject 프로퍼티 래퍼를 이용하여 참조해야 한다.
@EnvironmentObject var demoData : DemoData
또한 해당 객체는 관찰자인 Swift UI View 내부에서 초기화될 수 없다. 따라서 Swift UI가 화면을 구성하기 전에 초기화해주어야 하는데, 이를 위해 어플리케이션의 Entry Point 인 @main 함수를 찾아가보자
@main
struct IOSStudyApp: App {
@StateObject var demoData = DemoData()
var body: some Scene {
WindowGroup {
DemoDataView()
.environmentObject(demoData)
}
}
}
@StateObject 프로퍼티 래퍼로 감싸진 DemoData 인스턴스를 생성하고, View의 environmentObject 로 넘겨주자. @StateObject 는 ios14 에서 나온 것으로, 정확한건 다음 글에서 기술해야겠다. 이제 DemoDataView() 와 그 하위 뷰들은 모두 똑같은 demoData 인스턴스를 참조하게 된다.
똑같은 인스턴스를 참조하는지 확인하기 위해, 이전과 같이 유저 카운트를 증감시키는 뷰와, NavigationLink 로 두 번째 뷰로 이동하게 만들어 두 번째 뷰에서도 이전의 userCount 를 유지하는지 확인해보자.
struct DemoDataView : View {
@EnvironmentObject var demoData : DemoData
var body : some View {
VStack{
CountView(userCount: $demoData.userCount)
HStack{
Button(action:{demoData.userCount += 1}){
Text("더하기")
}
Button(action:{demoData.userCount -= 1}){
Text("빼기")
}
}
NavigationView{
NavigationLink(destination: SecondView(), label: {Text("두 번째 뷰로")})
.navigationBarHidden(true)
}
}
}
}
struct SecondView : View {
@EnvironmentObject var demoData : DemoData
var body: some View {
VStack{
Text("두 번째 뷰")
CountView(userCount: $demoData.userCount)
}
}
}
위 뷰에서 카운트를 3으로 변경하고, 두 번째 뷰로 이동해보았다.
모든 뷰에서 정상적으로 똑같은 DemoData 인스턴스를 참조하는 것을 확인했다.