← 아카이브로 돌아가기

Development · SwiftUI

@EnvironmentObject로 전역 상태 공유하기

여러 하위 뷰가 같은 ObservableObject를 공유할 때 @EnvironmentObject를 주입하고 읽는 방법을 살펴봅니다.

Velog 원문 보기 ↗

Development 아카이브 표지

상태를 여러 단계의 자식 뷰로 계속 전달하다 보면 데이터를 사용하지 않는 중간 뷰까지 매개변수를 갖게 된다. @EnvironmentObject는 공유 객체를 환경에 넣고 실제로 필요한 뷰가 직접 꺼내 쓰게 한다.

뷰 간 데이터 공유

ObservableObject를 채택한 객체 데이터를 @StateObject와 @ObservedObject를 통해 뷰 간에 공유할 수 있다. 하지만 이 방법은 직접적으로 데이터를 사용하지 않더라도 전달만을 위해 인스턴스를 생성해야하는 상황이 발생한다.

// 공유할 데이터
class EnvironmentViewModel: ObservableObject {
    
    @Published var dataArray: [String] = []
    
    init() {
        getData()
    }
    
    func getData() {
        self.dataArray.append(contentsOf: ["iPhone", "iPad", "iMac"])
    }
}

// 첫 번째 뷰
struct FirstView: View {
    
    // 데이터 생성
    @StateObject var viewModel: EnvironmentViewModel = EnvironmentViewModel()
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(viewModel.dataArray, id: \.self) { item in
                    NavigationLink {
                        SecondView(viewModel: viewModel, selectedItem: item)
                    } label: {
                        Text(item)
                    }
                }
            }
        }
    }
}

// 두 번째 뷰
struct SecondView: View {
    
    // 불필요한 데이터 전달
    @ObservedObject var viewModel: EnvironmentViewModel
    let selectedItem: String
    
    var body: some View {
        NavigationLink {
            ThirdView(viewModel: viewModel)
        } label: {
            Text(selectedItem)
        }
    }
}

// 세 번째 뷰
struct ThirdView: View {
    
    // 데이터 공유
    @ObservedObject var viewModel: EnvironmentViewModel

    var body: some View {
        ForEach(viewModel.dataArray, id: \.self) { item in
            Text(item)
        }
    }
}

@EnvironmentObject

@StateObject로 생성한 객체 데이터를 .environmentObject()를 통해 하위 뷰 전역에 공유할 수 있다. 공유 받은 하위 뷰에서는 데이터가 필요한 특정 뷰까지의 불필요한 전달없이 @EnvironmentObject를 통해 바로 사용할 수 있다.

struct FirstView: View {
    
    // 데이터 생성
    @StateObject var viewModel: EnvironmentViewModel = EnvironmentViewModel()
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(viewModel.dataArray, id: \.self) { item in
                    NavigationLink {
                        SecondView(selectedItem: item)
                    } label: {
                        Text(item)
                    }
                }
            }
        }
        // 하위 뷰 전역에 데이터 공유
        .environmentObject(viewModel)
    }
}

struct SecondView: View {
    
    // 불필요한 전달 없음
    let selectedItem: String
    
    var body: some View {
        NavigationLink {
            ThirdView()
        } label: {
            Text(selectedItem)
        }
    }
}

struct ThirdView: View {
    
    // 데이터 공유
    @EnvironmentObject var viewModel: EnvironmentViewModel
    
    var body: some View {
        ForEach(viewModel.dataArray, id: \.self) { item in
            Text(item)
        }
    }
}

← 아카이브로 돌아가기