@ObservableObject
- @ObservedObject는 ObservableObject 프로토콜을 준수하는 객체를 관찰하는 뷰 내에서 사용되는 프로퍼티 래퍼입니다.
- ObservableObject는 Class형태만 가능합니다. Struct형태는 불가능합니다.
- class의 @Published 인스턴스의 변화를 감지하고 해당 인스턴스가 변화할 때 마다 뷰를 업데이트합니다.
- ObservableObject 프로토콜을 준수하면 objectWillChange프로퍼티를 사용할 수 있습니다.
* @Published 어노테이션은 값이 변동되었을때 바로 View에게 즉각적으로 알려주는 어노테이션입니다.
ex)
class MyViewModel: ObservableObject {
@Published var score = 0
}
struct ContentView: View {
@ObservedObject var viewModel = MyViewModel()
var body: some View {
Text("Score: \(viewModel.score)")
.onTapGesture {
viewModel.score += 1
}
}
}
text의 TapGesture가 발생한경우 ViewModel의 score변수를 +1 증가시키게됩니다.
위 @Published를 사용하지 않았다면 단순히 ViewModel의 score가 +1 되겠지만 @Published이기 때문에 View에 바로 전달되어 +1된 Text가 즉시 업데이트됩니다.
* 위에 설명했듯 ObservableObject 프로토콜을 준수하면 objectWillChange프로퍼티를 사용할 수 있습니다.
ObjectWillChanged
인스턴스 내부 @Published값이 변경될 때 objectWillChange이벤트가 동작합니다.
objectWillChange.send()는 SwiftUI에 값이 변동됐음을 알려주는 메서드입니다.
class ViewModel: ObservableObject {
var score = 0 {
willSet(newValue) {
if score % 3 == 0 {
objectWillChange.send()
}
}
}
}
objectWillChange.send()는 SwiftUI에 값이 변동됐음을 알려주는 메서드라고 설명했듯 @Published가 아니여도 Published처럼 동작하게 만들 수 있습니다.
위의 score메서드는 @Published가 아님에도 objectWillChanged.send()를 직접 호출해줌으로써 SwiftUI에게 값의 변경을 알리고 UI가 업데이트되게됩니다.
class MyData: ObservableObject {
var number: Int {
willSet { self.objectWillChange.send() }
}
init(number: Int) {
self.number = number
}
}
var data = MyData(number: 20)
data.objectWillChange
.send()
data.objectWillChange
.sink { print("change value? = \($0)") }
data.number = 10
data.number = 1
// change value? = ()
// change value? = ()
만약 sink를 활용해 구독을 한다고 하면 값의 변경이 일어날 때 sink의 클로저를 실행하게 될것입니다.
objectWillChange는 객체의 @Published 프로퍼티 중 하나가 변경되기 전에 방출되는 publisher입니다. 그러나, 이는 실제 변경되는 값을 방출하지 않습니다.
@Published
위에 많이 등장했기 때문에 어느정도 감이 잡힐겁니다.
이는 클래스 내의 프로퍼티 앞에 선언되는 프로퍼티 래퍼입니다.
해당 프로퍼티의 값이 변경될 때 마다 구독자(subscriber)에게 알림을 보냅니다.
사용하기 위해선 프로퍼티가 속한 클래스가 Observable프로토콜을 준수해야합니다.
@Published 프로퍼티의 값이 변경되면 이를 관찰하는 SwiftUi 뷰는 자동으로 업데이트됩니다.