SwiftUI Study – @State / @Binding / @ObservedObject / @StateObject / @EnvironmentObject 정확한 역할 이해하기
Dev Study/SwiftUI 2025. 12. 9. 09:02반응형
SwiftUI Study – @State / @Binding / @ObservedObject / @StateObject / @EnvironmentObject 정확한 역할 이해하기
1. 왜 중요한가 (문제 배경)
SwiftUI의 핵심은 상태(State)입니다.
상태를 어디에 두느냐는 앱의 성능, UI 일관성, 렌더링 빈도, 유지보수성에 큰 영향을 줍니다.
많은 개발자가 다음과 같은 혼란을 겪습니다.
- @State와 @ObservedObject 차이를 모름
- ViewModel을 @ObservedObject로 선언해 매번 초기화됨
- @Binding 남용으로 부모·자식 간 상태가 꼬임
- @EnvironmentObject를 전역 변수처럼 사용해 의존성 증가
이 팁은 SwiftUI 상태 관리의 가장 중요한 원칙을 정리합니다.
2. 잘못된 패턴 예시
❌ 예시 1: ViewModel을 @ObservedObject로 선언해 매번 재생성됨
struct WrongView: View {
@ObservedObject var viewModel = UserViewModel() // ❌ 문제 발생
var body: some View {
Text(viewModel.name)
}
}
문제:
- @ObservedObject는 외부에서 주입될 때 적합한 방식
- 직접 생성하면 View가 다시 그려질 때마다 ViewModel이 재생성됨
- API 요청, 초기화 로직이 반복 실행됨 → 성능 저하 + 의도치 않은 사이드이펙트
❌ 예시 2: UI 상태와 도메인 상태를 섞음
struct WrongLoginView: View {
@State private var email = ""
@State private var password = ""
@State private var isLoading = false
@State private var isLoggedIn = false // ❌ 도메인 상태까지 UI에서 관리
var body: some View {
// 전체 로직이 View 내부 존재 → 테스트 불가능 구조
}
}
문제:
- UI 상태와 비즈니스 상태가 뒤섞임
- 다른 화면에서 재사용하기 어려움
- 유지보수 비용 증가
❌ 예시 3: 무분별한 Binding 전달로 상태 구조가 꼬임
struct ParentView: View {
@State private var isOn = false
var body: some View {
ChildSwitch(isOn: $isOn) // ❌ 항상 좋은 구조는 아님
}
}
문제:
- 자식이 부모 상태를 자유롭게 변경
- 상태 동기화 경로가 여러 군데로 확산
- 디버깅 어려움
❌ 예시 4: EnvironmentObject 남용
class AppState: ObservableObject {
@Published var user: User?
}
struct SomeView: View {
@EnvironmentObject var appState: AppState // ❌ 전역 변수처럼 사용
}
문제:
- 의존성이 숨겨져 있어 추적 어려움
- preview에서 제공 안 하면 크래시
- 상태 공유 범위가 과도해짐
3. 올바른 패턴 예시
✅ 예시 1: ViewModel은 @StateObject로 선언
struct UserProfileView: View {
@StateObject private var viewModel = UserViewModel() // 올바른 사용
var body: some View {
Text(viewModel.name)
}
}
장점:
- ViewModel이 한 번만 생성
- API 요청, Timer 등이 안정적으로 운용됨
✅ 예시 2: 도메인 상태는 ViewModel에서, UI 상태는 View에서 관리
struct LoginView: View {
@State private var email = ""
@State private var password = ""
@StateObject private var viewModel = LoginViewModel()
var body: some View {
VStack {
TextField("Email", text: $email)
SecureField("Password", text: $password)
Button("로그인") {
viewModel.login(email: email, password: password)
}
if viewModel.isLoading {
ProgressView()
}
}
}
}
✅ 예시 3: Binding 대신 단방향 데이터 흐름 유지
Child(
value: isOn,
onToggle: { isOn = $0 }
)
장점:
- 상태가 한 방향으로 흐름
- 예상 가능한 구조
✅ 예시 4: EnvironmentObject는 전역 상태일 때만 최소한으로
적절한 사용:
- UserSession
- AppSettings
- App-wide Permission State
부적절한 사용:
- 특정 화면에서만 필요한 ViewModel
- 단순 UI 상태
4. 실전 적용 팁
✔ 상태 소유권(Single Source of Truth)을 먼저 결정
SwiftUI 상태 설계에서 가장 중요한 질문:
“이 상태의 주인은 누구인가?”
- UI 자체: @State
- 부모 → 자식 변경 필요: @Binding
- ViewModel: @StateObject
- 외부에서 주입되는 모델: @ObservedObject
- 앱 전체 공유: @EnvironmentObject
✔ 단방향 데이터 흐름을 유지하라
SwiftUI는 React와 동일하게 단방향 데이터 흐름이 핵심입니다.
State → View → User Action → State 변경
Binding 남용은 이 구조를 혼란스럽게 만듦.
✔ ViewModel의 수명 주기는 @StateObject로 보장
Navigation 이동 시 ViewModel이 살아 있어야 한다면 반드시 @StateObject.
✔ 속성 래퍼 선택 기준표
| 상황 | 올바른 선택 |
| View 내부 전용 UI 상태 | @State |
| 부모 상태를 자식이 수정 | @Binding |
| 외부에서 주입된 ObservableObject | @ObservedObject |
| ViewModel처럼 View가 소유해야 할 객체 | @StateObject |
| 앱 전체에서 공유되는 전역 상태 | @EnvironmentObject |
5. 정리
- SwiftUI 상태 래퍼의 선택은 앱 구조의 절반 이상을 결정한다
- @StateObject와 @ObservedObject 혼동은 가장 흔한 실수
- Binding 남용은 단방향 상태 흐름을 깨뜨린다
- EnvironmentObject는 전역 상태일 때만 최소한으로
- UI 상태와 도메인 상태는 반드시 분리
상태만 올바르게 설계해도 SwiftUI 앱의 안정성은 크게 향상됩니다.
반응형
'Dev Study > SwiftUI' 카테고리의 다른 글
| SwiftUI Study – GeometryReader에 의존하지 않고 레이아웃을 안정적으로 구성하는 방법 (0) | 2025.12.09 |
|---|---|
| SwiftUI Study – 상태 변경을 한 곳으로 모으는 패턴 (0) | 2025.12.09 |
| SwiftUI Study – FocusState를 안전하게 설계하는 방법 (0) | 2025.12.09 |
| SwiftUI Study – 도메인 상태와 UI 상태를 분리하는 방법 (0) | 2025.12.09 |
| SwiftUI에서 많이 하는 실수 - Button 안에서 상태 변경 로직이 여러 계층에 중첩되어 UI가 비정상 업데이트되는 문제 (0) | 2025.12.08 |
| SwiftUI에서 많이 하는 실수 - 하나의 상태를 여러 곳에서 동시에 수정해 충돌이 나는 실수 (1) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - AppStorage / SceneStorage를 남용해 예기치 않은 상태 유지가 발생하는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - View 중첩이 지나치게 깊어져 가독성과 유지보수가 나빠지는 실수 (0) | 2025.12.05 |

