상태 프로퍼티는 하위뷰가 아니거나
State 바인딩이 구현되어 있지 않은 다른 뷰에서는 사용이 접근할 수 없다..
또 부모 뷰에 선언되어 있기 때문에 부모 뷰가 사라지면 프로퍼티 또한 사라져 버린다
여러 다른 뷰들이 외부에서 접근 가능한 지속적인 데이터를 표현하기 위해서는 Observable
객체를 사용할 수 있다.
어떻게 사용하나..?
import Foundation
//combine 프레임워크 삽입
import Combine
class MyData: ObservedObject {
//@Published 프로퍼티 래퍼를 통해 래퍼 프로퍼티 값이 변경 될때 마다 구독자에게 업데이트를 알림
@Published var userCount = 0
@Published var currentUser = ""
init() {
//데이터 초기화
updateData()
}
func updateData() {
//데이터 새로고침
}
}
import SwiftUI
struct ContevtView: View {
//@ObservedObject: 객체의 참조를 뷰가 소유하지 않음
//@StateObject: 객체의 참조를 뷰가 소유
@StateObject var myData: MyData = MyData()
//@ObservedObject var myData: MyData = MyData()
var body: some View {
Text("\(myData.currentUser) - \(myData.userCount)")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(myData: MyData())
}
}
@StateObject를 사용하면 참조를 선언한 뷰가 참조를 소유하게 되므로 해당 데이터를 계속 필요로 하는 동안에는 사라지지 않는다!(특별한 이유가 없다면 @StateObject를 사용)
구독되는 객체는 특정 상태가 앱 내의 몇몇 뷰에서 사용될 때 적합하다.
그런데 다른 뷰로 이동을 하면서 이동되는 뷰에서도 똑같은 구독 객체에 접근해야 한다면 어떻게 할까?
NavigatoinLink(destination: SecondeView(myData)) {}
위와 같이 해당 객체에 대한 참조를 전달하면 된다.
다만, 앱내의 여러 뷰가 동일한 구독 객체에 접근해야 한다면 전달이 복잡해진다..
이때 Enviroment
객체를 사용하는 것이 합리적일 수 있다.
import Foundation
import Combine
//Observable 객체와 같이 선언
class SpeedSetting: ObservedObject {
@Published var speed: 0.0
}
import SwiftUI
struct SpeedControlView: View {
//@EnvironmentObject 프로퍼티 래퍼 사용
@EnvironmentObject var speedsetting: SpeedSetting
var body: some View {
Slider(value: $speedSetting.speed, in: 0...100)
}
}
import SwiftUI
struct ContentView: View {
let speedSetting = SpeedSetting()
var body: some View {
SpeedControlView()
}.environmentObject(speedSetting)
//speedSetting 인스턴스를 계층 구조 전부에 주입
}
이렇게 하면 Observable객체와 같이 작동하지만 뷰 이동시에 계층 구조를 따라 전달되지 않고
ContentView
의 모든 하위 뷰에서 동일한 객체에 접근할 수 있다.
공식 문서 예제를 살펴보다 보니 Combine
프레임워크 관련 내용이 많아 이해가 어려웠다..ㅠ
추후 Combine
을 제대로 한번 다뤄야겠다.