- Total
꿈꾸는리버리
@EnvironmentObject ???? 본문
이번 포스팅에서는 @EnvironmentObject에 대해 알아보려 한다.
만약.. @StateObject와 @ObservedObject에 대해 모른다면 이전 포스팅 내용을 보고 공부를 하고 오는 게 ..!!
왜 @EnvironmentObject가 필요?
@StateObject와 @ObservedObject를 사용할 때에는 자식뷰 N에서 사용하기 위해서는
계속 자식뷰1->자식뷰2->자식뷰3 으로 ObservableObjec를 넘겨주는 작업이 필요했다.
근데 만약에 자식뷰2,3,4에서는 A가 필요없는데 자식뷰 5에서 필요하다면..?
그래도 자식뷰2,3,4를 거쳐 자식뷰5까지 A를 전달해줬어야 한다.
그래서 나타난 게 ! @EnvironmentObject !
요 칭구는 그림에서 봐도 알겠지만, 중간 중간에 띵가뽕이 가능하다 !
그렇다면 @EnvironmentObject 이제 왜 이런 이름이 붙었는지 감이 온다 ㅎㅎ
" 자식뷰들의 환경(?)에서 필요할 때만 사용할 수 있는 !! @EnvironmentObject "
어떻게 @EnvironmentObject를 사용하지 ?
1) ObservableObject 프로토콜을 준수하는 ViewModel 만들기
class River_ViewModel: ObservableObject {
@Published var name : String = "River"
}
2) RootView의 modifier에 ViewModel 인스턴스를 공유하겠다고 명시하기
struct EnvironmentObjectView: View {
@State var isSubView1 = false
@State var isSubView2 = false
var body: some View {
NavigationView{
VStack{
Text("RootView")
.font(.title)
.padding()
NavigationLink("SubView1", destination: EnvironmentObject_SubView1(),isActive: $isSubView1)
NavigationLink("SubView2", destination: EnvironmentObject_SubView2(),isActive: $isSubView2)
}
}.environmentObject(River_ViewModel()) // 이 부분 !
}
}
위 코드에서는 EnvironmentObjectView의 하위뷰인 SubView1와 SubView2에 River_ViewModel 인스턴스를 공유하였다.
3) 하위 뷰에서 @EnvironmentObject 프로퍼티래퍼로 받아서 쓰기
struct SubView1: View {
@EnvironmentObject var river: River_ViewModel // 이 부분 !
var body: some View {
VStack{
Text("SubView1")
.font(.title)
.padding()
Text("name : \(river.name)")
}
}
}
끝 !
💡 세부 설명
1) 원하는 View에서만 사용하기
안 쓸거면 @EnvironmentObject로 안 받으면 된다 ! 필요한 뷰에서만 사용하기 !
struct SubView2: View {
// SubView2에서는 River_ViewModel 인스턴스를 사용하지 않을 거니까
// @EnvironmentObject var river: River_ViewModel
// 위 코드는 안 적어도 된다 !
var body: some View {
VStack{
Text("SubView2")
.font(.title)
.padding()
Text("나눈 River_ViewModel 인스턴스 안 받았지렁이 ~")
}
}
}
2) Root뷰의 지짜짜 의미
위 그림과 같이 Root뷰1에서 modifier(.environmentObject)로 modelView의 인스턴스를 전달하면
Root 뷰1 안의 자식뷰만 사용할 수 있지,
Root뷰2와 그 자식뷰들에서는 사용하지 못한다.
그렇다면..
Root1과 Root2를 감싸는 진짜짜 Root뷰에서 modifier(.environmentObject)로 modelView의 인스턴스를 전달하면 되겠지..?
만약, 앱 전체에서 사용하는 ObservableObject라면,
최상위 뷰에서 modifier에 인스턴스를 공유하면 된다!
@main
struct DataFlowApp: App {
var body: some Scene {
WindowGroup {
EnvironmentObjectView()
.environmentObject(RiverViewModel())
}
}
}
3) preview에서 @EnvironmentObject 사용하기
struct EnvironmentObjectView_Previews: PreviewProvider {
static var previews: some View {
EnvironmentObjectView()
.environmentObject(River_ViewModel()) // 이케 해주면 된다규
}
}
정리
💡EnvironmentObject 사용법
1) ObservableObject 프로토콜을 준수하는 ViewModel 만들기
2) RootView의 modifier에 ViewModel 인스턴스를 공유하겠다고 명시하기
3) 필요한 하위 뷰에서만 @EnvironmentObject 프로퍼티래퍼로 받아서 쓰기
💡EnvironmentObject 언제 사용 ?
1) 대부분의 뷰에서 ObservableObject가 쓰이면서 중간에 띵가뽕하는 뷰들이 존재할 때
2) Data와 UI 사이의 Two-way Binding가 필요할 때
3) 여러개의 뷰에서 ObservableObject update가 동시에 필요할 때
전체 코드
import SwiftUI
class River_ViewModel: ObservableObject {
@Published var name : String = "River"
}
struct EnvironmentObjectView: View {
@State var isSubView1 = false
@State var isSubView2 = false
var body: some View {
NavigationView{
VStack{
Text("RootView")
.font(.title)
.padding()
NavigationLink("SubView1", destination: SubView1(),isActive: $isSubView1)
NavigationLink("SubView2", destination: SubView2(),isActive: $isSubView2)
}
}.environmentObject(River_ViewModel())
}
}
struct SubView1: View {
@EnvironmentObject var river: River_ViewModel
var body: some View {
VStack{
Text("SubView1")
.font(.title)
.padding()
Text("name : \(river.name)")
}
}
}
struct SubView2: View {
var body: some View {
VStack{
Text("SubView2")
.font(.title)
.padding()
Text("나눈 River_ViewModel 인스턴스 안 받았지렁이 ~")
NavigationLink("SubView2-1", destination: SubView1())
}
}
}
struct EnvironmentObjectView_Previews: PreviewProvider {
static var previews: some View {
EnvironmentObjectView()
.environmentObject(River_ViewModel())
}
}
'오뚝이 개발자 > SwiftUI' 카테고리의 다른 글
SwiftUI : Custom Color (0) | 2022.05.24 |
---|---|
SwiftUI : dark mode preview (0) | 2022.05.24 |
onAppear vs onRecieve (0) | 2022.05.01 |
AppStorage (1) | 2022.04.29 |
@StateObject vs @ObservedObject (2) | 2022.04.28 |