@StateObject @ObservedObject @EnvironmentObject

@StateObject 와 @ObservableObject 를 또 검색해보다가 이번에 그냥 직접 이것저것 해보면 기억에 남지 않을까 싶어서 실험해봤다. 궁금했던 건 RootView 아래에 ContentView 가 있고, ContentView 에서 각각 NavigationLink 와 sheet으로 NavigationLinkView 와 sheetView 에 연결된다고 할 때, source of truth 가 어디까지 자동으로 상속되는가!

그러니까 대충 이런 구조


struct Root: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: NavigationLinkView()) {
                    Text("contentView")
                }
            }
            .sheet(isPresented: $isPresented) {
                SheetView()
            }
        }
    }
}

1. Root 에서 environmentObject 로 넘기는 경우

struct Root: App {
    @StateObject var fromRoot = someClass() 
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(fromRoot)
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var fromRoot: someClass
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: NavigationLinkView()) {
                    Text("contentView")
                }
            }
            .sheet(isPresented: $isPresented) {
                SheetView()
            }
        }
    }
}

struct NavigationLinkView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}

struct SheetView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}
ContentViewNavigationLinkViewSheetView
상속 OOO

2. Root 에서 ObservedObject로 Contentview 에만 넘겨주는 경우

struct Root: App {
    @StateObject var fromRoot = someClass() 
    
    var body: some Scene {
        WindowGroup {
            ContentView(fromRoot: fromRoot)
        }
    }
}

struct ContentView: View {
    @ObservedObject var fromRoot: someClass
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: NavigationLinkView()) {
                    Text("contentView")
                }
            }
            .sheet(isPresented: $isPresented) {
                SheetView()
            }
        }
    }
}

struct NavigationLinkView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}

struct SheetView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}
ContentViewNavigationLinkViewSheetView
상속OXX

  1. ContentView 에서 @StateObject 를 선언하는 경우
  • 2와 동일한 상황
struct ContentView: View {
    @StateObject var fromContentView: someClass
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: NavigationLinkView()) {
                    Text("contentView")
                }
            }
            .sheet(isPresented: $isPresented) {
                SheetView()
            }
        }
    }
}

struct NavigationLinkView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}

struct SheetView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}
ContentViewNavigationLinkViewSheetView
상속OXX

4. 2,3번 상황에서 ContentView 의 VStack 에서 .environmentObject() 로 넘겨주는 경우

struct ContentView: View {
    @StateObject var fromContentView: someClass
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: NavigationLinkView()) {
                    Text("contentView")
                }
            }
            .sheet(isPresented: isPresented) {
                SheetView()
            }
            .enviromentObject(fromContentView)  // 여기
        }
    }
}

struct NavigationLinkView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}

struct SheetView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}
ContentViewNavigationLinkViewSheetView
상속OXO

# 5. 2,3번 상황에서 ContentView 의 NavigationView 에서 .environmentObject() 로 넘겨주는 경우

struct ContentView: View {
    @StateObject var fromContentView: someClass
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: NavigationLinkView()) {
                    Text("contentView")
                }
            }
            .sheet(isPresented: isPresented) {
                SheetView()
            }
        }
        .enviromentObject(fromContentView)  // 여기
    }
}

struct NavigationLinkView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}

struct SheetView: View {
    @EnvironmentObject var fromRootOrContentView: someClass
}
ContentViewNavigationLinkViewSheetView
상속OOO




# 결론

  • sheet, NavigationLink 등으로 연결되는 새로운 view 는 상위 view(e.g. RootView) 의 EnviromentObject 는 상속받으나, 연결이 시작된 view(e.g. ContentView) 의 EnvironmentObject 는 자동으로 상속받지 않는다.
  • NavigationLink 로 연결된 view 는 NavigationView 에 EnvironmentObject 주입해야 상속받을 수 있다

좋은 웹페이지 즐겨찾기