상태를 누가 소유하고 어떻게 전달해야 하는가
SwiftUI에서는 상태를 저장하거나 다른 뷰에 전달할 때 프로퍼티 래퍼를 사용한다.
이 상태를 현재 뷰가 직접 가지고 있는지, 부모 뷰에서 전달받는지, 아니면 별도의 객체가 관리하는지에 따라 사용하는 래퍼가 달라진다.
상위 뷰 → 하위 뷰
@State → @Binding상위 뷰가 상태를 소유하고, 하위 뷰는 해당 상태를 수정할 수 있도록 @Binding으로 전달받는다.
뷰 모델 → 뷰 → 하위 뷰
ObservableObject 프로토콜을 채택한 뷰 모델에서는, 변경을 알려야 하는 값을 @Published 프로퍼티로 선언한다.(이 뷰 모델을 뷰에서 주입받아 사용할 때는 보통 @ObservedObject로 관찰함)
뷰에서 값을 읽어서 보여줄 때는 그냥 써도 됨(viewModel.프로퍼티). 그런데 하위 뷰가 그 값을 수정해야 한다면, 값 자체가 아니라 바인딩을 넘겨야 한다($viewModel.프로퍼티).
그러면 하위 뷰에선 @Binding으로 해당 프로퍼티를 받아서 사용한다.
@StateObject는? → 뷰모델 직접 생성할때 사용
생각해볼것
@State로 쓰기 vs. View model로 관리하기
검색해보니 표현의 문제는 @State로, 도메인적 문제는 View model에 넣으라고 한다.
- 단순 시트/알럿 토글, 액션시트, 포커스 상태, 임시 입력 드래프트와 같은 건
@State로 관리하기 - 로그인 실패 후 “세션 만료” 알림과 같은 경우에는 View model로 관리하기
기준이 되게 자의적인 것 같음, 뭔가 기술적인 분류가 아니라. 팀 내부에서 정하는 문제.
어느 깊이까지 가야하는가. 고민해보기. 데이터가 어디까지 들어가는지…
추가. 멘토링 할 때 질문했는데, 지금 변경시킨 상태가 영속성이 있는지, 즉 DB에 들어갔다 나오는지를 판단해보라고 했다.
그런데 지금 적다보니 어디까지 DB에서 처리할지는 그것도 팀 나름 아닌가? 라는 생각이 좀 든다. 그런데 이렇게 하나하나 따지고 보면, 밑도 끝도 없으니까…
한 눈에 보기
| 속성 | 용도 | 언제 사용하는가 | 소유 관계 |
|---|---|---|---|
@State | SwiftUI에서 뷰 내부의 상태 변화를 추적하고, 상태가 변경되면 뷰를 다시 렌더링하도록 한다. | 뷰 내부에서 상태를 정의할 때 (로컬 상태) | 상태 소유 (뷰가 상태를 소유) |
@Binding | 부모 뷰에서 전달된 상태를 자식 뷰에서 사용하거나 수정할 수 있도록 연결할 때 사용된다. | 자식 뷰에서 상태를 전달받아 사용할 때 | 상태 소유 X (다른 뷰에서 전달받음) |
@StateObject | SwiftUI에서 객체를 처음 생성하고, 해당 객체의 상태를 뷰가 소유하며 관리할 때 사용한다. | 뷰 내부에서 상태 객체를 처음 생성할 때 (최초 소유) | 상태 소유 (뷰가 상태 객체를 소유) |
@ObservedObject | 외부에서 상태를 관리하는 객체를 뷰에서 구독하고, 해당 객체의 상태 변화에 따라 뷰를 다시 렌더링한다. | 외부에서 관리되는 상태 객체를 뷰에서 사용할 때 | 상태 소유 X (외부에서 관리) |
@EnvironmentObject | 공유된 데이터 모델을 여러 뷰에서 사용할 수 있도록 전달할 때 사용된다. SwiftUI 환경에서 자동으로 주입된다. | SwiftUI의 상위 뷰에서 공통으로 전달받은 객체를 하위 뷰에서 사용할 때 | 상태 소유 X (환경에서 전달받음) |
@Environment | SwiftUI에서 미리 정의된 환경 변수를 주입받아 사용할 때 사용된다. | 시스템 또는 부모 뷰에서 설정된 환경 값을 사용할 때 | 상태 소유 X (환경에서 전달됨) |
@Published | ObservableObject 프로토콜을 따르는 객체에서 특정 프로퍼티가 변경될 때 이를 자동으로 알림으로 보낸다. | 객체 내부에서 상태 변화를 알리고 싶을 때 | 상태 소유 (객체가 상태를 소유) |