SwiftUI Study – @EnvironmentObject 안전하게 사용하기 (크래시 방지·전역 상태 오염 방지)
Dev Study/SwiftUI 2025. 12. 9. 10:08SwiftUI Study – @EnvironmentObject 안전하게 사용하기 (크래시 방지·전역 상태 오염 방지)
1. 왜 중요한가 (문제 배경)
@EnvironmentObject는 SwiftUI에서 전역 공유 상태를 전달하는 강력한 도구입니다.
하지만 다음과 같은 상황에서 가장 치명적인 크래시를 유발하는 요소이기도 합니다.
- 상위 View에서 주입하지 않은 EnvironmentObject를 자식에서 참조
- NavigationStack 또는 sheet 경로에서 EnvironmentObject가 누락
- View 계층이 깊어지며 “어디서 주입됐는지” 파악이 어려워지는 문제
- 전역 상태를 너무 쉽게 공유하여 유지보수 어려움 발생
- 테스트 불가능한 구조가 되어 앱 안정성이 떨어짐
핵심 문제는 다음과 같습니다.
EnvironmentObject는 “필수 주입”인데도 컴파일 단계에서는 체크되지 않으며,
런타임에 누락되면 즉시 앱이 크래시 된다.
따라서 실무에서는 매우 신중하게 사용해야 한다.
2. 잘못된 패턴 예시
❌ 예시 1: 상위 뷰에서 주입하지 않았는데 자식에서 참조
struct WrongChildView: View {
@EnvironmentObject var session: SessionViewModel // ❌ 주입되지 않은 상태
var body: some View {
Text("User: \(session.name)")
}
}
상위 뷰:
RootView() // ❌ environmentObject를 붙이지 않음
문제점
- 앱 실행 시 즉시 크래시: “No ObservableObject of type SessionViewModel found”
- SwiftUI에서는 컴파일러가 잡아주지 않아 더 위험
❌ 예시 2: NavigationStack 내부에서 누락되는 문제
NavigationStack {
HomeView()
}
.environmentObject(SessionViewModel()) // ❌ NavigationStack 바깥에 있음
문제점
- iOS 17~18 일부 버전에서 자식 경로로 push된 화면이 EnvironmentObject를 상속받지 못하는 경우 있음
- 특히 sheet/presentation 경로에서 문제 발생 빈도 ↑
❌ 예시 3: 너무 많은 것을 EnvironmentObject로 전달
@EnvironmentObject var user: UserVM
@EnvironmentObject var settings: SettingsVM
@EnvironmentObject var theme: ThemeVM
@EnvironmentObject var session: SessionVM
문제점
- 전역 공유 상태가 난무해 구조 파악이 어려움
- 어디서든 수정 가능 → 사이드 이펙트 증가
- 테스트 불가능한 구조가 됨
3. 올바른 패턴 예시
✅ 예시 1: Root에서 명확하게 주입
@main
struct MyApp: App {
@StateObject private var session = SessionViewModel()
var body: some Scene {
WindowGroup {
RootView()
.environmentObject(session) // 정확한 주입 위치
}
}
}
장점
- 앱 전역에서 session을 안정적으로 사용 가능
- 크래시 위험 제거
- 데이터 수명주기 명확함
✅ 예시 2: NavigationStack “안쪽”에 주입
NavigationStack {
HomeView()
.environmentObject(session)
}
장점
- push/pop 되는 모든 화면에서 안전하게 전달
- sheet, fullScreenCover에서도 안정적 작동
- iOS 17~18 네비게이션 계층 문제 회피
✅ 예시 3: EnvironmentObject는 “정말 필요한 상태만” 제한적으로 사용
전역 상태로 적합한 경우
- 인증 정보(Session)
- 앱 전체에서 공유되는 사용자 설정 (Theme, Settings)
- 단일 인스턴스만 있어야 하는 객체
전역 상태로 부적합한 경우
- 특정 화면에서만 사용되는 ViewModel
- 일시적인 UI 상태
- 데이터 편집용 임시 모델
→ 이런 경우에는 EnvironmentObject 대신 @StateObject / @ObservedObject / @Bindable 등을 사용해야 함.
4. 실전 적용 팁
✔ 팁 1 – EnvironmentObject는 “전역 싱글톤”과 비슷한 개념
남용하면 구조가 망가진다.
✔ 팁 2 – 하나의 화면(View)에서 너무 많은 EnvironmentObject를 참조하지 말 것
상태 간 의존성이 복잡해지고 관리 불가능.
✔ 팁 3 – NavigationStack 내부에서 반드시 주입
환경 객체가 무조건 경로를 따라 전달되도록 보장됨.
✔ 팁 4 – 시트(sheet) · 풀스크린(fullScreenCover)에서는 특히 주입 여부 확인
이 경로에서 누락되는 경우가 가장 많음.
✔ 팁 5 – TCA(Composable Architecture) 사용 시 EnvironmentObject는 거의 필요 없음
Reducer·Store 구조가 상태 전달을 대신 처리하므로 더 안전하고 예측 가능.
5. 정리
- EnvironmentObject는 강력하지만 위험한 도구이며, 주입 누락 시 앱이 즉시 크래시된다.
- “전역 상태”에만 제한적으로 사용하고, 화면 단위 전용 상태는 다른 방식(@StateObject 등)으로 관리해야 한다.
- NavigationStack 내부 주입이 가장 안정적 구조이다.
- 올바른 사용 기준을 지키면 SwiftUI 상태 전달 문제를 크게 줄이고 유지보수성을 높일 수 있다.

