-
[iOS/Swift] @StateObject vs @ObservedObject야매 iOS 2023. 8. 7. 06:42
@StateObject와 @ObservedObject 모두 관찰하고 있는 객체에 변경이 생기면 이의 응답으로 SwiftUI 뷰를 갱신하게 한다.
@StateObject와 @ObservedObject 모두 ObservableObject를 준수하는 인스턴스만 감시할 수 있다.
- ObservableObject는 해당 인스턴스의 @Published 프로퍼티 값이 갱신되기 전에 변경된 값을 방출한다.
- 이때 뷰가 다시 그려진다.
class TempObservableObject: ObservableObject { @Published var name: String func changeName(to name: String) { // 이때 암시적으로 objectWillChange.send가 호출된다 self.name = name } }
StateObject와 ObservedObject의 차이?
- 뷰가 재생성할 때 감시중인 인스턴스 또한 재생성되는가의 차이
@ObservedObject
@ObservedObject property wrapper로 감시하고 있는 인스턴스는 뷰가 새로 그려질 때마다 재생성된다.
- 예를 들어 부모 뷰가 있고 자식 뷰가 있다. 그리고 자식 뷰는 @ObservedObject property wrapper로 갖는다.
- 이때 부모 뷰는 @State, @StateObject, @ObservedObject 프로퍼티의 값이 변경되었을 때 부모 뷰가 다시 그려진다.
- 부모 뷰에 포함되어 있는 자식 뷰도 다시 그려진다.
- 자식 뷰가 다시 그려지면서 자식 뷰가 갖고 있는 @ObservedObject 또한 재생성되며 이전의 상태값이 유실된다.
@StateObject
property wrapper로 감시하고 있는 인스턴스는 뷰는 처음 뷰가 생성될 때만 초기화된다.
- 다른 외부 요인에 영향을 받지 않고 뷰 자체의 상태를 가진다라고 유추할 수 있다
- 생성할 때의 차이
@ObservedObject
일반적으로 어느 인스턴스를 생성할 때 생성자로 필요한 매개변수를 넘겨줄 수 있다.
이와 같이 자식뷰가 @ObservedObject 프로퍼티를 갖고 있고 부모뷰가 자식뷰를 생성할 때 해당 인스턴스를 주입해줄 수 있다.
@StateObject
StateObject는 ObservedObject의 케이스와 다르게 부모뷰가 자식뷰를 생성할 때 해당 인스턴스를 주입할 수 없다.
필요한 값들을 생성자를 통해 넘겨주고 자식 뷰에서 그 값을 조합해 StateObject를 생성해야 한다.
class NameModel: ObservableObject { @Published var name: String } struct MyView: View { @StateObject private var model: NameModel init(name: Stiring) { _model = StateObject(wrappedValue: { NameModel(name: name) }()) } } struct ContentView: View { @State name: String = "name" var body: some View { MyView(name: name) } }
위와 같은 방식을 사용해 직접 StateObject를 생성했다면 ContentView에서 name이 변경되었을 때 그 변경된 값을 MyView는 전달받지 못한다.
- StateObject는 뷰가 처음 생성될 때만 초기화되기 때문
하지만 StateObject를 강제로 다시 초기화하게끔 할 수 있다.
- 뷰의 identity를 같이 변경시키면 된다.
하나의 값이 변경되었을 때 다시 초기화 하는 방법
var body: some View { MyView(name: name) .id(name) }
두 개 이상의 값이 변경되었을 때 다시 초기화 하는 방법
var hash: Int { var hasher = Hasher() hasher.combine(name) haser.combine(number) return hasher.finalize() } var body: some View { MyView(name: name) .id(hasher) }
왜?
왜 StateObject는 ObservableObject를 넘겨 받을 수 없을까라는 생각을 했다.
- 첫 번째 차이점으로 StateObject는 다른 외부 요인에 영향을 받지 않고 뷰 자체의 상태를 가지는 것을 알 수 있었다.
- ObservableObject는 기본적으로 class-bound를 가진다. 그러므로 call by value가 아닌 call by reference란 것을 알 수 있다
- reference로 전달하므로 상위 뷰에서의 변경이 자식뷰에도 영향을 있다.
- 그래서 @StateObject에게 인스턴스를 넘겨주는 것이 막혀 있지 않을까라는 생각이 든다.
'야매 iOS' 카테고리의 다른 글
[Swift] some & any (0) 2023.08.07 [Swift] Protocol Oriented Programming (0) 2023.08.07 [iOS/Swift] Operation (0) 2023.08.06 [iOS/Swift] 동시성 문제 (0) 2023.08.06 [iOS/Swift] DispatchGroup / Dispatch Work Item (0) 2023.08.06