@StateObject 및 @ObservedObject 프로퍼티 래퍼는 SwiftUI 보기에 관촬된 개체의 변경 사항에 대한 응답으로 업데이트하도록 지시합니다. 두 래퍼는 비슷해 보이지만 SwiftUI에서 앱을 빌드할때 중요한 차이점이 있습니다.
What is an @ObservedObject?
@StateObject와 @ObservedObject의 차이점을 알아보기 전 @ObservedObject가 무엇인지 이해하는 것이 좋습니다. 두 프로퍼티 래퍼 모두 개체가 ObservableObject 프로토콜을 준수해야 합니다. 이 프로토콜은 객체가 변경되기 전 방출하는 게시자가 있는 객체를 나타내며 SwiftUI가 뷰를 다시 그리기를 그리도록 지시할 수 있습니다.
ObservableObject
를 준수하는 타입은 @ObservedObject 프로퍼티 래퍼와 결합하여 SwiftUI 뷰를 연결하고 관찰된 객체 내에서 감지된 변경 후에 다시 그리도록 할 수 있습니다.
예를 들기 좋은 카운터 뷰 예제 입니다.
final class CounterViewModel: ObservableObject {
@Published var count = 0
func incrementCounter() {
count += 1
}
}
struct CounterView: View {
@ObservedObject var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count is: \(viewModel.count)")
Button("Increment Counter") {
viewModel.incrementCounter()
}
}
}
}
CounterViewModel이 ObservableObject
프로토콜을 따르기 때문에 뷰 모델을 @ObservedObject로 정의할 수 있습니다. 뷰 모델 내부의 count 프로퍼티는 버튼이 실행되면 증가하고 @Published
프로퍼티는 모든 관찰자가 변경된 신호를 수신하도록 합니다.
변경 사항이 관찰자를 통해 어떻게 위임되는지 더 잘 이해하기 위해 더 이상 @Published
프로퍼티 래퍼를 사용하지 않도록 위의 코드를 수정할 수 있습니다. 대신 관찰 가능한 객체 게시자를 사용하고 변경 신호를 수동으로 보냅니다
final class CounterViewModel: ObservableObject {
private(set) var count = 0
func incrementCounter() {
count += 1
objectWillChange.send()
}
}
증가 함수가 실행되면 보기가 계속 업데이트되는 것을 볼 수 있습니다. 대부분의 경우 objectWillChange.send()
메서드를 수동으로 호출할 필요가 없습니다. 그러나 게시된 여러 프로퍼티를 한 번에 업데이트하여 해당 프로퍼티를 일반 인수로 표시하고 대신 수동 신호를 사용하는 경우 더 나은 방법이 될 수 있습니다.
위의 예제는 SwiftUI 보기가 관찰된 객체 내부에서 감지된 변경 사항을 기반으로 다시 그리는 방법을 보여줍니다. 이제 @StateObject
프로퍼티 래퍼를 살펴보고 어떻게 다른지 살펴보겠습니다.
What is a @StateObject?
@StateObject 프로퍼티 래퍼는 @ObservedObject와 유사하게 작동 합니다. 대신 @StateObject 프로퍼티 래퍼를 사용하도록 이전 코드 예제를 변경할 수 있으며, 아무 것도 변경되지 않은 것 같습니다.
struct CounterView: View {
/// Using @StateObject instead of @ObservedObject
@StateObject var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count is: \(viewModel.count)")
Button("Increment Counter") {
viewModel.incrementCounter()
}
}
}
}
아무것도 바뀌지 않는다는 사실 떄문에 @ObservedObject를 자주 사용하기로 결정했습니다. 그러나 @ObservedObject 대신 @StateObject를 사용해야 할 떄를 명확히 하는 데에는 상당한 차이가 있습니다. @StateObject 프로퍼티 래퍼로 표시된 관찰된 객체는 포함하는 뷰 구조체가 다시 그려질 때 파괴되거나 다시 인스턴스화되지 않습니다. 다른 보기에 사용자의 보기가 포함된 경우 이 차이점을 이해하는 것이 필수적입니다.
이것이 어떻게 작동하는 보여주기 위해 이전에 사용된 카운터 뷰를 다른 뷰 안에 래핑할 수 있습니다.
struct RandomNumberView: View {
@State var randomNumber = 0
var body: some View {
VStack {
Text("Random number is: \(randomNumber)")
Button("Randomize number") {
randomNumber = (0..<1000).randomElement()!
}
}.padding(.bottom)
CounterView()
}
}
랜덤 보기에는 랜덤 버튼을 눌러 랜덤숫자를 생성할 수 있습니다. @State
프로퍼티 래퍼로 표시된randomNumber
프로퍼티는 뷰를 다시 그려 CounterView
가 재생성되도록 합니다.
새로운 랜덤숫자가 생성되면 CounterView
내에서 @ObservedObject
를 사용하면 카운터가 재설정되는 것을 볼 수 있습니다.
@ObservedObject | @StateObject |
---|---|
수정은 CounterView
보기 모델 프로퍼티를 @ObservedObject 대신 @StateObject로 변경하는 것 입니다.
위에서 설명된 것처럼 상태 객체는 뷰 모델이 다시 그리기 간에 유지되도록 하고 카운터 값이 동일하게 유지 되도록 합니다.
So, when should I use a @StateObject?
이제 둘 다 어떻게 작동하는지 알고 있지만 @ObservedObject 프로퍼티 래퍼 대신 @StateObject를 사용하는 경우를 더 긍정적으로 생각해도 좋습니다.
SwiftUI가 언제든지 뷰를 생성하거나 다시 생성할 수 있기 때문에 뷰 내부에 @ObserverdObject를 생성하는 것은 안전하지 않습니다. @ObservedObject를 종속성으로 주입하지 않는 한 뷰를 다시 그린 후 일관된 결과를 보장하기 위해 @StateObject 래퍼를 사용하는게 좋습니다.
Should I use @StateObject for all views using the same instance?
라인 아래에서 동일한 @StateObject 인스턴스를 관찰하는 형제는 이 프로퍼티 래퍼로 개체를 표시할 필요가 없습니다. 두 곳에서 개체의 수명 주기를 유지하고 관리하도록 요청할 것이므로 이렇게 하지 않는 것이 중요 합니다. 이전 섹션에서 설명한 것처럼 관찰된 개체를 주입하는 경우 @ObservedObject를 사용해야 합니다.
결국 차이점
@ObservedObject
@ObservedObject
결국 View에 종속되는 느낌. ObservableObject
에서 데이터 변화가 있다면 View를 처음부터 다시 그려진다. 또한 View와 생명주기를 같이 하며, View가 사라지면 @ObservedObject
의 인스턴스도 사라지고, View가 다시 그려지면 @ObservedObject
의 인스턴스도 사라졌다가 다시 생성된다.
@StateObject
@StateObject
반대로, View에 종속되지 않는다. 데이터의 변화가 있다면 View를 처음부터 다시 그리는 것이 아니라, 그 데이터를 사용하는 부분만 다시 그린다. View가 사라지든 다시 생기든 신경 안쓰고 알아서 있는 느낌. View와 생명주기가 따로 논다.
참고 링크
@StateObject vs. @ObservedObject: The differences explained
'iOS > SwiftUI' 카테고리의 다른 글
SwiftUI TextField (0) | 2023.11.10 |
---|---|
SwiftUI ZStack 활용 (0) | 2023.11.07 |
SwiftUI) NavigationBar 뒤로가기 버튼 안보이게 하기 (0) | 2023.06.12 |
SwiftUI) List NavigationLink item ">" 숨기는 방법 (0) | 2023.05.31 |
SwiftUI alert in iOS14 (0) | 2023.01.17 |