일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- Git
- SWIFTUI
- singleton
- IOS
- self
- viewlifecycle
- 고차함수
- segue
- escaping
- PushNotification
- uikit
- apns
- NotificationCenter
- Refresh
- Switch
- error
- protocol
- array
- calendar
- SWIFT
- struct
- 글또
- class
- 회고
- ScrollView
- list
- http
- mvvm
- Observer
- 화면전환
- Today
- Total
seong_hye, the developer
Swift) StateObject, ObservableObject, EnvironmentObject 본문
모두 데이터와 뷰 상태를 연결하기 위한 속성 래퍼이다
이들은 각각의 역할과 적용 범위, 생명주기가 다르기 때문에 구분해서 사용하는 것이 중요하다
📘 ObservableObject
SwiftUI에서 클래스 기반 상태를 뷰와 연결해주는 핵심 프로토콜
뷰가 해당 객체를 구독하고 내부 값이 바뀌면 뷰가 자동으로 업데이트됨
주로 크래스를 기반으로하는 뷰모델을 만들 때 사용함
🔹예시
// 상태 객체 선언
class CounterModel: OBsrvableObject {
@Published var count = 0
}
// 뷰에서 연결
struct TestView: View {
@ObservedObject var viewModel: CounterModel
var body: some View {
VStack {
Button("값 추가") {
viewModel.count += 1
}
}
}
}
✅@Published
@Published는 @ObservableObject의 필수 파트
@Published가 붙은 프로터티가 바뀌면, 뷰에 변경 신호가 전달됨
값이 바뀔 때 Combine의 Publisher를 통해 objectWillChange를 자동으로 호출함
🔹특징
ObservableObject는 클래스에서만 사용 가능 (구조체 X)
@Published를 빼먹으면 뷰가 갱신되지 않음
뷰가 제대로 연결되지 않으면 생명주기나 상태가 꼬일 수 있음
🔹사용 경우
로그인 상태 관리 | 여러 뷰에 로그인 상태 전파 |
API 통신 결과 저장 | 비동기 결과를 반영해 뷰 업데이트 |
사용자 설정 관리 | 다수 뷰에서 공통 데이터 접근 |
📘 StateObject
클래스 기반의 상태 객체(ObservableObject)를 뷰에서 직접 생성하고 소유할 때 사용하는 속성 래퍼
뷰가 직접 상태를 소유하고 유지함
뷰의 생명주기와 함께 객체의 생명주기도 관리됨
~> 다시 생성되더라도 @StateObject는 한 번만 생성됨
🔹사용하는 이유?
@ObservedObject만 쓰던 초기에 문제가 있었음
- 뷰가 재생성될 때마다 @ObservedObejct가 새로 생성됨 -> 상태 초기화 문제 발생
- 이를 방지하기 위해 소유하고 있는 상태 객체에는 @StateObejct를 써야한다는 개념이 생김 (iOS 14부터 도입)
🔹예시
// 상태 객체 선언
class CounterModel: OBsrvableObject {
@Published var count = 0
}
// 뷰에서 연결
struct TestView: View {
@StateObject var viewModel = CounterModel()
var body: some View {
VStack {
Button("값 추가") {
viewModel.count += 1
}
}
}
]
✅@StateObject를 사용하는 경우
상황 | 사용해야 하는가? |
뷰 안에서 ObservableObject를 직접 만들 때 | O (@StateObject) |
부모 뷰에서 넘겨받은 상태를 관찰할 때 | X (@ObservedObject) |
여러 뷰에서 공유해야 할 때 (전역 상태) | X (@EnvironmentObject) |
✅@ObservedObject vs @StateObject
속성 | 객체 생성 | 생명주기 관리 | 사용 위치 |
@StateObject | 해당 뷰에서 생성 | SwiftUI가 관리 | "처음"상태 객체 생성 시 |
@ObservedObject | 외부에서 주입됨 | 외부에서 관리 | 자식 뷰에서 상태 관찰만 할 때 |
✅생명주기 예시
//잘못된 예시
struct WrongView: View {
@ObservedObject var modal = CounterModel() // 잘못된 사용 (매번 초기화됨)
}
//올바른 예시
struct CorrectView: View {
@StateObject var modal = CounterModel() // 한 번만 초기화
}
🔹요약
항목 | 설명 |
의미 | ObservableObject를 뷰가 소유할 때 사용하는 속성 |
역할 | 한 번만 초기화되고 뷰 재생성 시에도 유지 |
도입 시기 | iOS 14부터 |
보통 사용 위치 | 상태 객체를 직접 생성하는 최상위 뷰 |
내부에서 사용되는 기술 | Combine의 objectWillChange 구독 |
📘 EnvironmentObject
상위에서 주입한 전역 상태 객체를 하위 뷰에서 쉽게 공유할 수 있도록 도와주는 속성 래퍼
SwiftUI 환경에 저장하고 공유하는 방법
상위 뷰에서 .envrionmentObject(_:)로 전달된 객체를 하위 뷰에서 @EnvironmentObject로 꺼내서 사용
큰 앱일수록 복잡한 데이터 전달 없이 전역 상태를 깔끔하게 관리할 수 있음
🔹기본 상태 흐름
//상태 객체 정의
class UserSettings: ObservableObject {
@Published var username: String = "홍길동"
}
// 최상위 뷰에서 .environmentObejct()로 주입
@main
struct TestApp: App {
var settings = UserSettings()
var body: some Scene {
WindowGroup {
ContentView()
.environment(settings) // 전역 상태 주입
}
}
}
// 하위 뷰에서 @EnvironmentObject로 사용
struct ContentView: View {
@Environment var settings: UseSettings // 공유 상태 접근
var body: some View {
VStack {
Text("사용자 이름: \(settings.username)")
Button("이름 변경") {
settings.username = "이순신
}
}
}
}
📌 상위 뷰에서 .environmentOjbect()로 주입하지 않으면 런타임 오류 발생
⚠️Fatal error: No ObservableObject of type UserSettings found in environment
🔹사용하는 경우
- 앱 전체에서 공통 데이터를 공유하고 싶을 때
- 부모 -> 자식 -> 손자 뷰로 데이터 전달하는 게 귀찮을 때
- 의존성 주입처럼 객체를 context에서 꺼내 쓰고 싶을 때
🔹장점과 단점
장점 | 단점 |
상위에서 한 번만 주입하면 하위 전체에서 사용 가능 | 주입 누락 시 런타임 오류 발생 |
코드가 간결해짐(prop drilling 제거) | 의존성이 명시적이지 않음 (숨겨짐) |
앱 전체 전역 상태 공유에 적합 | 너무 많이 사용하면 구조가 애매해질 수 있음 |
🔹요약
항목 | 설명 |
타입 | ObservableObject의 전역 공유 |
사용 위치 | 주로 상위 앱/루트 뷰 |
연결 방식 | .environmentObject(_:) -> @EnvironmentObject |
대표 예시 | 로그인 상태, 사용자 정보, 테마, 설정 등 |
🔹핵심 차이 비교
속성 | 사용 위치 | 객체 생성 위치 | 사용 목적 | 소유자 |
@StateObject | 뷰 내부 | 뷰 내부에서 생성 | 상태를 직접 소유 | 해당 뷰 |
@ObservedObject | 뷰 내부 | 외부에서 전달 | 상태를 구독만 | 부모 뷰 등 |
@EnvironmentObject | 전역 공유 | 상위 환경에서 주입 | 전역 상태 공유 | 전역 (App, Scene 등) |
🔹사용하는 경우 차이
상태 객체를 처음 생성해야 함 -> @StateObject
이미 만들어진 객체를 자식 뷰에 넘김 -> @ObservedObject
상위 뷰에서 전체 앱에 공유하고 싶음 -> @EnvironmentObject
'IOS' 카테고리의 다른 글
Swift) 구조적 특징에 대해 알아보기 (0) | 2022.12.16 |
---|---|
Swift) 동기 vs 비동기에 대해서 알아보기 (0) | 2022.11.10 |
Swift) Error Code (0) | 2022.10.28 |
Swift) Library, Framework, Package에 대해 정리하기 (0) | 2022.10.24 |
Swift) APNs 설정 방법 알아보기 (0) | 2022.10.23 |