반응형
LinkedIn 개발자로 성장하면서 남긴 발자취들을 확인하실 수 있습니다.
Github WWDC Student Challenge 및 Cherish, Tiramisul 등 개발한 앱들의 코드를 확인하실 수 있습니다.
개인 앱 : Cherish 내 마음을 들여다보는 시간, 체리시는 디자이너와 PM과 함께 진행 중인 1인 개발 프로젝트입니다.
10년 후, 20년 후 나는 어떤 스토리 텔러가 되어 있을지 궁금하다. 내가 만약에 아직 조금 더 탐구하고 싶은 게 있고, 궁금한 게 있다면, 그게 설사 지금 당장의 내 인생에 도움이 안 되는 것 같더라도 경험해보자. 그 경험들을 온전히 즐기며 내 것으로 만들고, 내 일에 녹여내고... 그러다보면 그 점들이 모여 나란 사람을 그려내는 선이 될 테니까.

Recent Posts
Recent Comments
Total
관리 메뉴

꿈꾸는리버리

@EnvironmentObject ???? 본문

오뚝이 개발자/SwiftUI

@EnvironmentObject ????

rriver2 2022. 5. 1. 11:25
반응형

이번 포스팅에서는 @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
Comments