오늘의 내용은?
앞에서 뷰 상태변경 제1장에 관하여 포스팅을 하였습니다. 오늘은 또다른 뷰 상태변경에 대해서 알아보도록 하겠습니다.
@StateObject
SwiftUI에서 상태변경를 위에서 자주 쓰이는 property wrapper중 하나인데 공식문서에서는 아래와 같이 정의가 되어있습니다.
- 관찰이 가능한 객체를 인스턴스화하는 property wrapper입니다.
- @StateObject의 목적: @StateObject 속성 래퍼는 관찰 가능한 객체(observable object)를 생성하고 관리하는 데 사용되며, 특정 뷰 내에서 단일 진리의 원천 역할을 합니다. 이 객체는 뷰의 생명주기 동안 단 한 번 초기화됩니다.
- 사용방법
- DataModel이라는 클래스는 객체가 변경될때 감지하고 업데이트해주는 ObservableObject 프로토콜을 따릅니다. 각 변수에 @Published로 선언하며 값이 변경될때마다 자동적으로 뷰를 업데이트하도록 설정되어있습니다.
- MyView에서 DataModel을 @StateObject 선언하며 이 인스턴스를 해당뷰에서 관리하도록 설정합니다.
- 관찰이 가능한 model같은 경우 .environmentObject(model)를 통해서 하위 뷰인 MySubView()에서도 접근이 가능하게 설정이 되어있습니다.
클래스와 같은 객체를 관리하고 뷰에서 인스턴스화된 변수에 접근하여 값이 변경시 자동적으로 뷰를 업데이트를 해주게 됩니다. 인스턴스는 한번만 생성하여 하위뷰에 .environmentObject(변수) 형식으로 접근할 수 있게 만들어 줍니다.
@StateObject 예시
음악앱에 대한 클래스를 생성하였습니다. musicName은 곡의 이름이며 isPlay는 현재 재생중인지 상태를 표현해줍니다.
- ContentView에서 @StateObject를 사용하여 클래스를 인스턴스화하여 play로 선언해주었습니다.
- Vstack으로 현재 노래이름과 재생 상태를 play변수에 접근하여서 보여주고 있습니다. 이때 play.isPlay가 true이면 재생중을 false이면 일시정지를 출력하여줍니다.
- Button을 활용하여 play.isPlay에 접근하여 클릭시 toggle 함수를 활용하여 상태를 반대로 변경하여 줍니다.
영상을 확인하면 알 수 있듯이 Button을 클릭시 재생상태가 실시간으로 변경되고 있음을 학인할 수 있습니다. 하나의 변수가 아닌 객체 자체를 관리해주고 실시간으로 뷰를 그려줍니다.
import SwiftUI
class Player: ObservableObject{
@Published var musicName: String = "RESCUE"
@Published var isPlay: Bool = false
}
struct ContentView: View {
@StateObject var play = Player()
var body: some View {
VStack(spacing: 20){
Text("노래이름: \\(play.musicName)")
Text("재생 상태: \\(play.isPlay == true ? "재생중" : "일시정지")")
Button(action: {
play.isPlay.toggle()
}, label: {
Text("재생 버튼")
})
}
.padding()
}
}
#Preview {
ContentView()
}
@ObservedObject
앞에서 배운 @Binding 기억하시나요? Binding과 비슷한 역할을 합니다.
- 관찰 가능한 객체를 구독하고 관찰 가능한 객체가 변경될 때마다 보기를 무효화하며 자동으로 업데이트해주는 property wrapper 유형입니다.
- @ObservedObject의 역할: 부모 뷰로부터 전달된 ObservableObject 객체를 자식뷰에서 구독하여 @Published 속성이 변경될 때마다 뷰를 업데이트할 수 있게 해줍니다.
- @StateObject가 객체의 생명주기를 관리하는 반면, @ObservedObject는 외부에서 전달받은 객체를 구독하기만 합니다.
@ObservedObject는 부모로 부터 받은 ObservableObject 객체를 활용하여 데이터를 업데이트 하고 사용할 수 있게 만들어줍니다.
@ObservedObject 예시
두개의 뷰에서 @ObservedObject을 활용하여 하나의 인스턴스에 구독하여 노래제목을 변경하는 예시입니다.
- 위에서 보여준 예시와 처음에는 동일하며 새로운 버튼을 통해서 changeModal이 true 값으로 변경되면 sheet가 나타나게 됩니다. sheet는 SubView를 보여줍니다.
- 하위뷰는 상위뷰에서 받은 play 인스턴스를 구독하여서 play.musicName을 변경할 수 있습니다.
- 이후 sheet를 내릴 경우 정상적으로 상위뷰에서도 노래 이름이 변경된것을 확인할 수 있습니다.
import SwiftUI
class Player: ObservableObject{
@Published var musicName: String = "RESCUE"
@Published var isPlay: Bool = false
}
struct ContentView: View {
@StateObject var play = Player()
@State var changeModal: Bool = false
var body: some View {
VStack(spacing: 20){
Text("노래이름: \\(play.musicName)")
Text("재생 상태: \\(play.isPlay == true ? "재생중" : "일시정지")")
Button(action: {
play.isPlay.toggle()
}, label: {
Text("재생 버튼")
})
Button(action: {
changeModal.toggle()
}, label: {
Text("노래 변경하기")
})
}
.padding()
.sheet(isPresented: $changeModal, content: {
SubView(play: play)
})
}
}
struct SubView: View {
@ObservedObject var play: Player
var body: some View {
VStack(alignment: .leading, spacing: 0){
Text("노래 변경")
Text("아래의 노래 제목을 변경하여 주세요")
TextField("노래 변경", text: $play.musicName)
.padding(.top, 20)
}
.padding()
}
StateObject와 ObservedObject을 통해서 뷰 간에 객체를 손 쉽게 사용할 수 있고 변경하며 자동으로 뷰 업데이트 해줍니다.
이렇게 오늘은 뷰 상태변경을 정리해보았습니다. 다음 내용은 아직 고민을 조금 해보아야할것 같아요. 부족한 내용이지만 끝까지 읽어봐주셔서 감사합니다. 지인에게 추천받은 개발자 속담으로 마무리하도록 하겠습니다! 파이팅입니다~
“의외로 컴퓨터는 거짓말을 하지 않는다.”
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] @Published 썼는데도 View가 안 바뀐다? (0) | 2025.05.30 |
---|---|
[SwiftUI] Splash & Onboarding 화면 구현 리뷰 (Feat. 나만의 Todo) (1) | 2025.05.26 |
[SwiftUI] Figma 비율 그대로! 개발하는 Constants 구조체 만들기 (1) | 2025.05.24 |
뷰 상태변경 제 1장 (0) | 2024.11.13 |
Property Wrapper (2) | 2024.09.22 |